Analysis of cacheName in asp. net template engine Razor

  • 2021-07-01 07:05:50
  • OfStack

This article illustrates the problem of cacheName in asp. net template engine Razor. Share it for your reference. The details are as follows:

1. Why use cacheName

The main reason for using cacheName is that Razor. Parse () will dynamically create an assembly every time it is parsed. If the parsing amount is large, many assemblies will be generated, and a large number of assembly calls will cause the program to be very slow.

For example:

If you compile 1000 times, the compilation speed will be very slow.


static void Main(string[] args)
{
 string cshtml = File.ReadAllText(@"E:\ Baiduyun synchronization disk \Study\Net_ASP.NET\Web Fundamental principles \RazorCacheNameTest\HTMLPage1.cshtml");
 for (int i = 0; i < 1000; i++)
 {
  string html = Razor.Parse(cshtml); 
 }
 Assembly[] asms = AppDomain.CurrentDomain.GetAssemblies();
 foreach (Assembly asm in asms)
 {
  Console.WriteLine(asm.FullName+"\r\n");
 }
 Console.ReadKey();
}

2. How to solve this problem

When using Razor. Parse (), take the cacheName parameter.

Specify an cacheName called cc, which will not be recompiled the next time Parse () is parsed. (Unless cshtml is modified, the cacheName name will also be renamed, allowing Parse () to parse the new file.)


for (int i = 0; i < 1000; i++)
{
  // If you call 1000 Second, many assemblies will be created in the following way, and the performance is very low 
  string html = Razor.Parse(cshtml); 
  // Analytic cshtml I gave you the file 1 The "cache name" is cc , this time 1 Once the compilation is successful 
  // Let you next time Parse() cc You don't have to compile repeatedly , It will be very fast, 
  // Unless cshtml Content modification 
  Razor.Parse(cshtml, null, "cc");
}

3. How can I determine that the file represented by cacheName has been modified?

There are two ways, one is the full file path + file modification time, and it can also be based on the MD5 value of cshtml file.


for (int i = 0; i < 10; i++)
{
  string cshtml = File.ReadAllText(fullPath);
  string cacheName = fullPath + File.GetLastWriteTime(fullPath);
  // Full file path + On a file 1 Time of second modification 
  string html = Razor.Parse(cshtml,null,cacheName);
  Console.WriteLine(html);
  Console.ReadKey();
}

Whenever the cshtml file is modified, the value of cacheName changes, and Parse () determines whether to recompile according to the cacheName value. If the cshtml file is modified three times during the test, three assemblies will eventually be generated, and if the cshtml file is not modified, only one assembly will eventually be generated.

Note: Questions about cacheName.

After experiments, it is found that even if cacheName is written as a fixed value, when cshtml changes, the result of Parse is also modified. Why?

After decompiling, we found that the Parse method finally called the GetTemplate method of TemplateService, and the code is as follows:


private ITemplate GetTemplate<T>(string razorTemplate, object model, string cacheName)
{
 Func<string, CachedTemplateItem, CachedTemplateItem> updateValueFactory = null;
 CachedTemplateItem item;
 if (razorTemplate == null)
 {
  throw new ArgumentNullException("razorTemplate");
 }
 int hashCode = razorTemplate.GetHashCode();
 if (!this._cache.TryGetValue(cacheName, out item) || (item.CachedHashCode != hashCode))
 {
  Type templateType = this.CreateTemplateType(razorTemplate, (model == null) ? typeof(T) : model.GetType());
  item = new CachedTemplateItem(hashCode, templateType);
  if (updateValueFactory == null)
  {
   updateValueFactory = (n, i) => item;
  }
  this._cache.AddOrUpdate(cacheName, item, updateValueFactory);
 }
 return this.CreateTemplate(null, item.TemplateType, model);
}

The general idea of the code is: find out whether there is a cache item "TryGetValue (cacheName, out item)" whose name is equal to cacheName from the cache cache, and if it does not exist, compile and create it; If it exists, then check whether the hashCode of the cshtml content in the cache (the signature of the string, the HashCode1 sample of the same string, and the probability of HashCode of different strings has 1 sample) and the HashCode of the incoming razorTemplate are 1 sample, and if not, recompile and create it without using the cached one.

Therefore, this can explain why with a fixed cacheName, as long as the content of cshtml is modified, Parse will still produce new content.

Some students will ask: Since the new content of Parse will be re-added after modifying cshtml, what's the significance of cacheName? This is because the probability that HashCode of different strings is the same is very low, but it is not without the possibility that "A and B are not the same, but hashcode is the same". Therefore, if only HashCode is relied on, there is such a probability that "the file of cshtml has been modified, but the modified HashCode is the same as before, so Parse still executes the old logic". Therefore, adding cacheName is "double insurance".

I hope this article is helpful to everyone's asp. net programming.


Related articles: