To generate random numbers

To generate random numbers:


public class TestClass
{
  private RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider();
  private byte[] _uint32Buffer = new byte[4];

  public int RandomNext(int min, int max)
  {
    if (min >= max)
    {
      return min;
    }

    long diff = max + 1 - min;

    while (true)
    {
      _rng.GetBytes(_uint32Buffer);
      uint rand = BitConverter.ToUInt32(_uint32Buffer, 0);

      long lMax = (1 + (long)uint.MaxValue);
      long remainder = lMax % diff;

      if (rand < lMax - remainder)
      {
        return (int)(min + (rand % diff));
      }
    }
  }

  private void ToTest()
  {
    StringBuilder log = new StringBuilder();
    for (int i = 0; i < 1000; i++)
    {
      log.Append(RandomNext(0, 1)).AppendLine();
    }

    WriteLog(log.ToString());
  }
}

 
“Since the numerator is the only place that we can introduce randomness, and since a Double is 64 bits long, rather than generating a UInt32 and dividing by UInt32.MaxValue+1, we could try generating a random UInt64 and dividing by UInt64.Max + 1, thereby doubling the amount of random bits in the input.
This, unfortunately, leads to another problem. Double-precision numbers store an approximation of a real number; System.Double, which complies with the IEEE 754 standard for binary floating-point arithmetic, provides at most 17 decimal digits of precision. Unfortunately, UInt64.MaxValue (18446744073709551615) requires 20 decimal digits of precision. As a result, under .NET floating-point arithmetic, UInt64.MaxValue is equal to UInt64.MaxValue + 1, and, thus, substituting UInt64 for UInt32 in our NextDouble equation will change our range from [0.0, 1.0) to [0.0, 1.0], which violates the design of System.Random’s implementation."

“For an example that demonstrates this skewing, let’s say we want a number in the range [21, 27]. (For this example, we’ll be selecting 8 bits rather than 32 bits just because it’s easier for demonstration, but the principle generalizes out to the 32 bits we’d actually be working with.) Following the equation shown earlier, we’ll now take a random number between 0 and 255 mod 6 + 21 to get our value. If the random number is in the range [0, 251] this works out great as each of the numbers [0,5] has come up exactly 42 times. However, once we move past 251, we’ll get 0 (252), 1 (253), 2 (245), and 3 (255) as values from our mod operation. That means that 0, 1, 2, and 3 have a 43/256 chance of being selected by the mod operation while 4 and 5 only have a 42/256 chance. Therefore, we’ve got a ~16.80 percent chance of getting 21, 22, 23, or 24 back, but only a ~16.41 percent chance of getting 25 or 26 back. Over the long term, if we were an attacker trying to guess outputs, we would be more successful by always choosing a number at the low end of the range."

“As we saw in the previous example, the favoritism happens when the randomly selected value satisfies the following condition:


RandomValue >= RandomRange - (RandomRange % TargetRange)

In our previous example, the RandomRange is 256 and the TargetRange is 6; therefore, favoritism happens when the RandomValue is >= 252."

 
Reference:

1) .NET Matters: Tales from the CryptoRandom https://docs.microsoft.com/en-us/archive/msdn-magazine/2007/september/net-matters-tales-from-the-cryptorandom

2) Buffered CryptoRandom implementation based on Stephen Toub and Shawn Farkas’ CryptoRandom https://gist.github.com/niik/1017834

3) RNGCryptoServiceProvider – generate number in a range faster and retain distribution? https://stackoverflow.com/questions/6299197/rngcryptoserviceprovider-generate-number-in-a-range-faster-and-retain-distribu

4) How do I generate a random int number? https://stackoverflow.com/questions/2706500/how-do-i-generate-a-random-int-number

 

TVP in SQL Server

Table-Valued Parameters (TVP) in SQL Server:

1. Create Type [TVP_Int]:


USE [DB01]
GO

CREATE TYPE [dbo].[TVP_Int] AS TABLE(
    [Val] [int] NOT NULL,
    PRIMARY KEY CLUSTERED 
    (
        [Val] ASC
    )WITH (IGNORE_DUP_KEY = OFF)
)
GO

 

SSMS : programmability => Types => User-Defined Table Types;

 
2. Stored Procedure:


CREATE PROCEDURE [dbo].[List_TestInfo] 
  @IDs As TVP_Int Readonly

AS
BEGIN

  SET NOCOUNT ON;

  SELECT 
    ID, Name 
  FROM
    TestInfo WITH(NOLOCK) 
  WHERE 
    ID IN (SELECT Val FROM @IDs)

END

 

3. Test SP:


DECLARE @Tbl AS [TVP_Int];
INSERT INTO @Tbl (Val) VALUES (1001)
INSERT INTO @Tbl (Val) VALUES (1002)
INSERT INTO @Tbl (Val) VALUES (1003)

EXEC [List_TestInfo]
    @IDs = @Tbl 

 

4. (C#) Convert SqlParameter (List to DataTable):


private DataTable ToDataTable<T>(List<T> list)
{
  DataTable t = new DataTable();
  t.Columns.Add("Val", typeof(T));

  foreach (var i in list)
  {
    t.Rows.Add(i);
  }

  return t;
}

 

Reference:

1) SQL 2008 TVP資料匯入之火力展示 https://blog.darkthread.net/blog/import-with-sql-tvp
2) SqlBulkCopy Vs. TVP Vs. XML Parameter Vs. Individual Insert Procs for 20-200 Inserts? https://stackoverflow.com/questions/8618261/sqlbulkcopy-vs-tvp-vs-xml-parameter-vs-individual-insert-procs-for-20-200-ins
3) Table-Valued Parameters https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/table-valued-parameters

 

API response caching

API response caching:


public class CacheBase
{
  protected int _expireDuration;
  protected long _cacheTimestamp;

  public int KeyMaxCount { get; set; }
  public dynamic SingleData { get; set; }
  public List<dynamic> ListOfData { get; set; }

  public CacheBase()
  {
    KeyMaxCount = 2000;
  }

  public bool IsExpire()
  {
    if (CurrentTimestamp() - _cacheTimestamp < _expireDuration)
    {
      return false;
    }

    return true;
  }

  protected long CurrentTimestamp()
  {
    return (long)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
  }
}

 


public class Person
{
  public int ID { get; set; }
  public string Name { get; set; }
}

public class PersonCache : CacheBase
{
  public PersonCache(List<Person> dataList)
  {
    _expireDuration = 20;
    _cacheTimestamp = CurrentTimestamp();

    if (dataList != null)
    {
      DataList = dataList.Cast<dynamic>().ToList();
    }
  }
}

 


protected bool IsCacheExpire<U>(ConcurrentDictionary<string, U> cacheDict, string key, out U cache)
	where U : CacheBase
{
  cache = default(U);
  if (cacheDict.TryGetValue(key, out cache) && cache != null
    && !cache.IsExpire())
  {
    return false;
  }

  if (cache != null && cacheDict.Count > cache.KeyMaxCount)
  {
    CleanCache(cacheDict);
  }

  return true;
}

protected void CleanCache<U>(ConcurrentDictionary<string, U> cacheDict)
  where U : CacheBase
{
  if (cacheDict == null || cacheDict.Count == 0)
  {
    return;
  }

  NLog.Logger logger = NLog.LogManager.GetLogger("CleanCache");
  StringBuilder log = new StringBuilder();

  try
  {
    LogCache(cacheDict, ref log);

    U got;
    foreach (var cache in cacheDict)
    {
      if (cache.Value != null && cache.Value.IsExpire())
      {
        cacheDict.TryRemove(cache.Key, out got);
      }
    }

    log.AppendLine("[After clean]");
    LogCache(cacheDict, ref log);
    logger.Info(log.ToString());
  }
  catch (Exception ex)
  {
    logger.Error(ex, log.ToString());
  }
}

protected void LogCache<U>(ConcurrentDictionary<string, U> cacheDict, ref StringBuilder log)
{
  if (cacheDict == null || cacheDict.Count == 0)
  {
    return;
  }

  log.AppendFormat("Cache Count: {0}", cacheDict.Count).AppendLine();
  log.Append("Keys: ");
  foreach (var cache in cacheDict)
  {
    log.AppendFormat("{0},", cache.Key);
  }
  log.AppendLine();
}

protected void AddNewCache<T>(ConcurrentDictionary<int, T> cacheDict, int key, T data)
{  //To reset the Cache Timestamp.
  T cache;
  if (cacheDict.TryGetValue(key, out cache))
  {
    cacheDict.TryRemove(key, out cache);
  }
  cacheDict.TryAdd(key, data);
}

 


private static ConcurrentDictionary<int, PersonCache> _personCacheDict = new ConcurrentDictionary<int, PersonCache>();

public List<Person> GetPeople(int keys)
{

  #region Query from cache

  uncachedKeys = new List<int>();
  List<Person> rtn = new List<Person>();

  foreach (int key in keys)
  {
    PersonCache cache;
    if (!IsCacheExpire<PersonCache>(_personCacheDict, key, out cache) 
      && cache.DataList != null)
    {
      cache.DataList.ForEach(data => rtn.Add(data));
    }
    else
    {
      uncachedKeys.Add(key);
    }
  }

  #endregion

  #region Query from db

  List<Person> dbDataList = QueryFromDB(uncachedKeys);

  if (dbDataList.Count == 0)
  {
    return rtn;
  }

  #endregion

  #region Write into the cache

  foreach (int key in uncachedKeys)
  {
    List<Person> list = (from p in dbDataList where p.ID == key select p).ToList();
    AddNewCache(_personCacheDict, key, new PersonCache(list));
  }

  #endregion

  return rtn.AddRange(dbDataList);
}

 

.NET DateTime

.NET DateTime:


StringBuilder log = new StringBuilder();

log.Append("DateTime.Now:\t").Append(DateTime.Now).AppendLine();
log.Append("DateTime.UtcNow:\t").Append(DateTime.UtcNow).AppendLine().AppendLine();

log.Append("DateTime.Now.ToLocalTime():\t").Append(DateTime.Now.ToLocalTime()).AppendLine();
log.Append("DateTime.UtcNow.ToLocalTime():\t").Append(DateTime.UtcNow.ToLocalTime()).AppendLine().AppendLine();

log.Append("DateTime.Now.ToUniversalTime():\t").Append(DateTime.Now.ToUniversalTime()).AppendLine();
log.Append("DateTime.UtcNow.ToUniversalTime():\t").Append(DateTime.UtcNow.ToUniversalTime()).AppendLine().AppendLine();

log.Append("new DateTime(2019,5,1,0,0,0,0):\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, 0)).AppendLine();
log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Unspecified):\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Unspecified)).AppendLine().AppendLine();

log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Local):\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Local)).AppendLine();
log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Local).ToLocalTime():\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Local).ToLocalTime()).AppendLine();
log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Local).ToUniversalTime():\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Local).ToUniversalTime()).AppendLine().AppendLine();

log.Append("new DateTime(2019,5,1,0,0,0,0).ToLocalTime():\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, 0).ToLocalTime()).AppendLine();
log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Unspecified).ToLocalTime():\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Unspecified).ToLocalTime()).AppendLine().AppendLine();

log.Append("new DateTime(2019,5,1,0,0,0,0).ToUniversalTime():\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, 0).ToUniversalTime()).AppendLine();
log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Unspecified).ToUniversalTime():\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Unspecified).ToUniversalTime()).AppendLine().AppendLine();

log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Utc):\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Utc)).AppendLine();
log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Utc).ToLocalTime():\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime()).AppendLine();
log.Append("new DateTime(2019,5,1,0,0,0,DateTimeKind.Utc).ToUniversalTime():\t").Append(new DateTime(2019, 5, 1, 0, 0, 0, DateTimeKind.Utc).ToUniversalTime()).AppendLine().AppendLine();

WriteLog(log.ToString());

 

Result:

Snipaste_2019-05-16_19-29-29

Snipaste_2019-05-17_18-04-26.png

 

 

Static member in C#

Static members in different objects from the same type refer to the same reference.


public class Obj
{
  private static string _static { get; set; }

  public string StaticValue 
  {
    get { return _static; }
    set { _static = value; }
  }
}


private void Test()
{
  StringBuilder log = new StringBuilder();

  Obj obj_1 = new Obj();
  obj_1.StaticValue = "1";

  WriteLog(string.Format("obj_1: {1}{0}", Environment.NewLine, obj_1.StaticValue));

  Obj obj_2 = new Obj();
  obj_2.StaticValue = "2";

  WriteLog(string.Format("obj_1: {1}, obj_2: {2}{0}", Environment.NewLine, obj_1.StaticValue, obj_2.StaticValue));

  Obj obj_3 = new Obj();
  obj_3.StaticValue = "3";

  WriteLog(string.Format("obj_1: {1}, obj_2: {2}, obj_3: {3}{0}", Environment.NewLine, obj_1.StaticValue, obj_2.StaticValue, obj_3.StaticValue));

  return;
}

 

Result:

Snipaste_2019-05-13_17-33-40.png

 

Deep Copy in C#

Deep Copy in C#:

1) Shallow Copy:

For a reference type, the clone refer to the same memory address.

1.1) Shallow Copy about object:

Snipaste_2019-04-18_15-41-48

 
1.2) Shallow Copy about Dictionary:

Snipaste_2019-04-18_15-37-06

 
1.3) Shallow Copy an array:


Person[] newArr = arr;

 

2) Deep Copy:

For a reference type, the clone refer to a new memory address.

2.1) Deep Copy an array:


public class Person
{
  public int Age { get; set; }
  public string Name { get; set; }

  public Person Clone()
  {
    Person p = new Person();
    p.Age = this.Age;
    p.Name = this.Name;

    return p;
  }
}

 


List<Person> list = new List<Person>();

//Can't modify an array within foreach.
for (int i = 0; i < arr.Length; i++)
{
  list.Add(arr[i].Clone());
}
Person[] newArr = list.ToArray();

 

2.2) Deep Copy using JSON Serialization:


/// <summary>
/// Deep Copy (Private members are not cloned using this method.)
/// </summary>
public static T CloneJson<T>(this T source)
{            
  if (Object.ReferenceEquals(source, null))
  {
    return default(T);
  }

  // initialize inner objects individually
  // for example in default constructor some list property initialized with some values,
  // but in 'source' these items are cleaned -
  // without ObjectCreationHandling.Replace default constructor values will be added to result
  var deserializeSettings = new JsonSerializerSettings {ObjectCreationHandling = ObjectCreationHandling.Replace};

  return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}

 

 

Reference:

1. [C#.NET] 淺複製與深複製 https://dotblogs.com.tw/yc421206/archive/2011/06/17/28785.aspx

2. Deep cloning objects https://stackoverflow.com/questions/78536/deep-cloning-objects/78612#78612

3. Fast array copy in C# https://stackoverflow.com/questions/23248872/fast-array-copy-in-c-sharp?lq=1

4. Modify array with Array.Foreach and lambda expression https://stackoverflow.com/questions/17037459/modify-array-with-array-foreach-and-lambda-expression

5. How to delete an element from an array in C# https://stackoverflow.com/questions/496896/how-to-delete-an-element-from-an-array-in-c-sharp

6. C# List<T>.ToArray performance is bad? https://stackoverflow.com/questions/1147497/c-sharp-listt-toarray-performance-is-bad

7. .NET data structures: ArrayList, List, HashTable, Dictionary, SortedList, SortedDictionary — Speed, memory, and when to use each? https://stackoverflow.com/questions/128636/net-data-structures-arraylist-list-hashtable-dictionary-sortedlist-sorted

8. In .NET, which loop runs faster, ‘for’ or ‘foreach’? https://stackoverflow.com/questions/365615/in-net-which-loop-runs-faster-for-or-foreach/365658#365658

 

.NET Remoting and WCF

.NET Remoting and Windows Communication Foundation (WCF):

.NET Remoting
  (not recommended)

WCF

Platform required
Microsoft OS and .NET Only Cross-platform
Data model
   & Interface Library (for Reference)
By-value types in Remoting are marked with the [Serializable] attribute or implement ISerializable: Create classes marked with the [DataContract] attribute.
The individual properties we want visible to both client and server are marked with [DataMember].
If we want derived types to be allowed, we must use the [KnownType] attribute to identify them.

[Serializable]  
public class Customer  
{  
  public string FirstName { get; set; }

  public string LastName { get; set; }

  public int CustomerId { get; set; }
}


[DataContract]  
[KnownType(typeof(PremiumCustomer))]  
public class Customer  
{  
  [DataMember]  
  public string FirstName { get; set; }  

  [DataMember]  
  public string LastName { get; set; }  

  [DataMember]  
  public int CustomerId { get; set; }  
}  

[DataContract]  
public class PremiumCustomer : Customer   
{  
  [DataMember]  
  public int AccountId { get; set; }  
}

The public methods of this server type become the public contract available to clients. Define a public interface and mark it with the [ServiceContract] attribute.
Methods available to clients are marked with [OperationContract].

public interface ICustomerService  
{  
  Customer GetCustomer(int customerId);  
}


[ServiceContract]  
public interface ICustomerService  
{  
  [OperationContract]  
  Customer GetCustomer(int customerId);  

  [OperationContract]  
  bool UpdateCustomer(Customer customer);  
}

[Server] Define public methods
.NET Remoting server types must derive from MarshalByRefObject. WCF:

public class CustomerService 
    : MarshalByRefObject, ICustomerService 
{  
  public Customer GetCustomer(int customerId)
  {
  }

  public override Object InitializeLifetimeService()
  {
    //Let MarshalByRefObject 
    // never expire.
    return null;
  }
}


public class CustomerService 
    : ICustomerService  
{  
  public Customer GetCustomer(int customerId)  
  {  
  }  

  public bool UpdateCustomer(Customer customer)  
  {  
  }  
}

[Server] Start the Server service
.NET Remoting: Declare an endpoint that exposes that service interface at a specific URL using a specific WCF binding.

TcpChannel channel = new TcpChannel(8000);  
ChannelServices.RegisterChannel(
  channel, 
  ensureSecurity : true);
RemotingConfiguration.RegisterWellKnownServiceType(  
  typeof(CustomerService),   
  "CustomerService",   
  WellKnownObjectMode.Singleton);


NetTcpBinding binding = new NetTcpBinding();  
Uri baseAddress = new Uri("net.tcp://localhost:8000/CustomerService");  
  
using (ServiceHost serviceHost = new ServiceHost(
    typeof(CustomerService), baseAddress))  
{  
  serviceHost.AddServiceEndpoint(
    typeof(ICustomerService), 
    binding, 
    baseAddress);  
  serviceHost.Open();  
}

[Client] Implementation
The CustomerService instance returned from Activator.GetObject() is known as a “transparent proxy". Use a channel factory to create the proxy explicitly.
Like Remoting, the proxy object can be used to invoke operations on the server.
The channel implements the service’s interface and handles the underlying request/reply logic.

TcpChannel channel = new TcpChannel();  
ChannelServices.RegisterChannel(
  channel, 
  ensureSecurity : true);
CustomerService server = (CustomerService)Activator.GetObject(  
  typeof(CustomerService),   
  "tcp://localhost:8000/CustomerService");  
  
Customer customer = server.GetCustomer(42);  

Console.WriteLine($"Customer {customer.FirstName} {customer.LastName} received.");


NetTcpBinding binding = new NetTcpBinding();  
String url = "net.tcp://localhost:8000/CustomerService";  
EndpointAddress address = new EndpointAddress(url);  

ChannelFactory channelFactory =   
  new ChannelFactory(binding, address);  
ICustomerService server = channelFactory.CreateChannel();  
  
Customer customer = server.GetCustomer(42);  

Console.WriteLine($"  Customer {customer.FirstName} {customer.LastName} received.");

Scenario: Client: Sends Server a By-Value Instance

ChannelFactory factory =  
  new ChannelFactory("customerservice");  
ICustomerService service = factory.CreateChannel();  
PremiumCustomer customer = new PremiumCustomer {   
  FirstName = "Bob",   
  LastName = "Jones",   
  CustomerId = 43,   
  AccountId = 99};  
bool success = service.UpdateCustomer(customer);  

Console.WriteLine($"  Server returned {success}.");

Reference:
1) 從 .NET 遠端處理移轉到 WCF https://docs.microsoft.com/zh-tw/dotnet/framework/wcf/migrating-from-net-remoting-to-wcf
2) 閒談:.NET Remoting、WCF、WebAPI、Socket,該怎麼選? https://blog.darkthread.net/blog/remoting-wcf-webapi-choice

Run-time exception about type dynamic and type object

Run-time exception about type dynamic and type object in C#:


public void Print(string arg)
{
    return;
}

 

A) Compiler error:


// A.1) Compiler error:
//  At compile time the type of obj is System.Object.
object obj = 10;
obj = obj + 10;  //obj = (int)obj + 10;

 


// A.2) Compiler error.
object obj = 10;  //object obj = "10";
Print(obj);       //Print((string)obj);

 

B) Run time exception:


// B.1) Run time exception: obj is an integer, not a string.
object obj = 10;
obj = (string)obj + 10;  //obj = (int)obj + 10;

 


// B.2) Run time exception: Cast to a wrong numeric type.
object obj = 10;
obj = (double)obj + 10;  //obj = (int)obj + 10;

 


// B.3) Run time exception.
object obj = 10;     //object obj = "10";
Print((string)obj);  //Print((string)obj);

 


// B.4) Run time exception:
//  The only way you can pass a dynamic object
//  to your method is if it contains a necessary value.
dynamic dyn = 10;  //dynamic dyn = "10";
Print(dyn);

 

C) No error:


// C.1) No error:
object obj = 10;
obj = (int)obj + 10;

 


// C.2) No error: The compiler does not try to identify
//  the type of the dynamic object at compile time.
dynamic dyn = 10;
dyn = dyn + 10;

 


// C.3) No error:
//  Success for all other types that support a “+” operation.
dynamic dyn = 10.0;
dyn = dyn + 10;
dyn = "10";
dyn = dyn + 10;

 


// C.4) No error: Still need a cast.
object obj = "10";
Print((string)obj);

 


// C.5) No error.
dynamic dyn = "10";
Print(dyn);

 

 

Reference:

What is the difference between “dynamic” and “object” keywords? https://blogs.msdn.microsoft.com/csharpfaq/2010/01/25/what-is-the-difference-between-dynamic-and-object-keywords

Simple insights into creating GUID

Simple insights into creating GUID (Globally Unique Identifier, Universally Unique Identifier):


// Test code.
// e.g. 3fca05e7-0bd8-47c2-92ac-690cb78f1fc2
string guid = Guid.NewGuid().ToString();

 


// Test code.
private string RandomString(int length)
{
  const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  uint validLength = (uint)valid.Length;

  StringBuilder builder = new StringBuilder();
  byte[] uintBuffer = new byte[4];
  using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
  {
    while (length-- > 0)
    {
      rng.GetBytes(uintBuffer);
      uint num = BitConverter.ToUInt32(uintBuffer, 0);
      builder.Append(valid[(int)(num % validLength)]);
    }
  }

  return builder.ToString();
}

 


// System
// .Guid
// This will create a new guid.  Since we've now decided that constructors should 0-init,
// we need a method that allows users to create a guid.
[System.Security.SecuritySafeCritical]  // auto-generated
public static Guid NewGuid() {
  // CoCreateGuid should never return Guid.Empty, since it attempts to maintain some
  // uniqueness guarantees.  It should also never return a known GUID, but it's unclear
  // how extensively it checks for known values.
  Contract.Ensures(Contract.Result<Guid>() != Guid.Empty);

  Guid guid;
  Marshal.ThrowExceptionForHR(Win32Native.CoCreateGuid(out guid), new IntPtr(-1));
  return guid;
}

 


// Microsoft.Win32
// .Win32Native
[DllImport(OLE32)]
[ResourceExposure(ResourceScope.None)]
internal extern static int CoCreateGuid(out Guid guid);

 


// https://source.winehq.org/WineAPI/CoCreateGuid.html
// Declared in "objbase.h". https://source.winehq.org/source/include/objbase.h
// Implemented in "dlls/ole32/compobj.c". https://source.winehq.org/source/dlls/ole32/compobj.c
// Debug channel "ole".
2094 /******************************************************************************
2095  *      CoCreateGuid [OLE32.@]
2096  *
2097  * Simply forwards to UuidCreate in RPCRT4.
2098  *
2099  * PARAMS
2100  *  pguid [O] Points to the GUID to initialize.
2101  *
2102  * RETURNS
2103  *  Success: S_OK.
2104  *  Failure: HRESULT code.
2105  *
2106  * SEE ALSO
2107  *   UuidCreate
2108  */
2109 HRESULT WINAPI CoCreateGuid(GUID *pguid)
2110 {
2111     DWORD status;
2112
2113     if(!pguid) return E_INVALIDARG;
2114
2115     status = UuidCreate(pguid);
2116     if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
2117     return HRESULT_FROM_WIN32( status );
2118 }

 


// https://source.winehq.org/source/dlls/rpcrt4/rpcrt4_main.c#0306
0291 /*************************************************************************
0292  *           UuidCreate   [RPCRT4.@]
0293  *
0294  * Creates a 128bit UUID.
0295  *
0296  * RETURNS
0297  *
0298  *  RPC_S_OK if successful.
0299  *  RPC_S_UUID_LOCAL_ONLY if UUID is only locally unique.
0300  *
0301  * NOTES
0302  *
0303  *  Follows RFC 4122, section 4.4 (Algorithms for Creating a UUID from
0304  *  Truly Random or Pseudo-Random Numbers)
0305  */
0306 RPC_STATUS WINAPI UuidCreate(UUID *Uuid)
0307 {
0308     RtlGenRandom(Uuid, sizeof(*Uuid));
0309     /* Clear the version bits and set the version (4) */
0310     Uuid->Data3 &= 0x0fff;
0311     Uuid->Data3 |= (4 << 12);
0312     /* Set the topmost bits of Data4 (clock_seq_hi_and_reserved) as
0313      * specified in RFC 4122, section 4.4.
0314      */
0315     Uuid->Data4[0] &= 0x3f;
0316     Uuid->Data4[0] |= 0x80;
0317 
0318     TRACE("%s\n", debugstr_guid(Uuid));
0319 
0320     return RPC_S_OK;
0321 }

 


// https://source.winehq.org/source/include/ntsecapi.h#0457
0457 #define RtlGenRandom    SystemFunction036

 


// https://source.winehq.org/source/dlls/advapi32/crypt.c#2374
2360 /******************************************************************************
2361  * SystemFunction036   (ADVAPI32.@)
2362  *
2363  * MSDN documents this function as RtlGenRandom and declares it in ntsecapi.h
2364  *
2365  * PARAMS
2366  *  pbBuffer [O] Pointer to memory to receive random bytes.
2367  *  dwLen   [I] Number of random bytes to fetch.
2368  *
2369  * RETURNS
2370  *  Success: TRUE
2371  *  Failure: FALSE
2372  */
2374 BOOLEAN WINAPI SystemFunction036(PVOID pbBuffer, ULONG dwLen)
2375 {
2376     int dev_random;
2377
2378     dev_random = open("/dev/urandom", O_RDONLY);
2379     if (dev_random != -1)
2380     {
2381         if (read(dev_random, pbBuffer, dwLen) == (ssize_t)dwLen)
2382         {
2383             close(dev_random);
2384             return TRUE;
2385         }
2386         close(dev_random);
2387     }
2388     else
2389         FIXME("couldn't open /dev/urandom\n");
2390     SetLastError(NTE_FAIL);
2391     return FALSE;
2392 }  

 

Theory of random number generator ( http://lxr.linux.no/linux/drivers/char/random.c ):

Computers are very predictable devices. Hence it is extremely hard to produce truly random numbers on a computer — as opposed to pseudo-random numbers, which can easily generated by using a algorithm. Unfortunately, it is very easy for attackers to guess the sequence of pseudo-random number generators, and for some applications this is not acceptable. So instead, we must try to gather “environmental noise" from the computer’s environment, which must be hard for outside attackers to observe, and use that to generate random numbers.

add_device_randomness():
This would be things like MAC addresses or serial numbers, or the read-out of the RTC (Real-time clock).

add_input_randomness():
uses the input layer interrupt timing, as well as the event type information from the hardware.

add_interrupt_randomness():
uses the interrupt timing as random inputs to the entropy pool. Using the cycle counters and the irq (Interrupt Request) source as inputs, it feeds the randomness roughly once a second.

add_disk_randomness():
uses what amounts to the seek time of block layer request events, on a per-disk_devt basis, as input to the entropy pool.

 

Reference:

(1) mscorlib https://referencesource.microsoft.com/#mscorlib/system/guid.cs,1152
(2) 好問題:GUID 真的不會重複嗎? https://blog.darkthread.net/blog/is-guid-really-unique
(3) using RNGCryptoServiceProvider to generate random string https://stackoverflow.com/questions/32932679/using-rngcryptoserviceprovider-to-generate-random-string
(4) Random vs. Pseudorandom Number Generators https://www.youtube.com/watch?v=itaMNuWLzJo
(5) win32pal.c https://github.com/fixdpt/shared-source-cli-2.0/blob/master/pal/win32/win32pal.c
(6) What entropy sources are available on Windows? https://stackoverflow.com/questions/4955527/what-entropy-sources-are-available-on-windows
(7) What is the most secure seed for random number generation? https://stackoverflow.com/questions/3436376/what-is-the-most-secure-seed-for-random-number-generation
(8) RtlGenRandom/CryptGenRandom or other WinAPI to generate cryptographically secure random numbers (first quarter of 2018) https://stackoverflow.com/questions/48875929/rtlgenrandom-cryptgenrandom-or-other-winapi-to-generate-cryptographically-secure
(9) linux/drivers/char/random.c http://lxr.linux.no/linux/drivers/char/random.c
(10) Pseudo Random Number Generators in Programming Languages http://portal.idc.ac.il/en/schools/cs/research/documents/sinai_2011.pdf
(11) Interrupt Request (IRQ) https://bcc16.ncu.edu.tw/pool/1.14.shtml