CreateOutputCachedItemKey caches the creation of key

  • 2020-05-19 04:32:21
  • OfStack

For information about OutputCache, you can see a little bit about OutputCacheProvider OutputCache. Let's review the content of OutputCache. OutputCache is to register ResolveRequestCache and UpdateRequestCache in OutputCacheModule class. The cache content is divided into two parts, part 1 is the cache policy CachedVary, part 1 is the cache data CachedRawResponse, a page cache policy only has one CachedVary, but it can have multiple cache content CachedRawResponse. The retrieval and setting of cache content is mainly dependent on GetSnapshot() UseSnapshot(HttpRawResponse rawResponse, bool sendBody) methods of HttpResponse. It is important to minimize the number of copies of the cached content. So let's take a look at how the cache key is created. The creation of key depends on the CreateOutputCachedItemKey method. The CreateOutputCachedItemKey method is a bit more complex, so let's take a look at its implementation.

How is the CreateOutputCachedItemKey method called? The code for creating the cache policy key: this.CreateOutputCachedItemKey (context, null); The code that creates the cache key: this.CreateOutputCachedItemKey (context, cachedVary) differs in that the parameter CachedVary has a value of null and an actual CachedVary instance. The code I have here is decompiled by Reflector.exe, which feels a little different from the real code, but logically 1.
I will use a practical example to change the analytic edge. Here, I set up an demo using asp.net mvc. Request url: http: / / localhost: 7503 / Home/index path should be: Home/index
First of all, we need to distinguish whether our request is Get or Post. Post starts with a1, otherwise a2 starts, followed by the current Path:
 
if (verb == HttpVerb.POST) 
{ 
builder = new StringBuilder("a1", path.Length + "a1".Length); 
} 
else 
{ 
builder = new StringBuilder("a2", path.Length + "a2".Length); 
} 
builder.Append(CultureInfo.InvariantCulture.TextInfo.ToLower(path)); 

By this time our caching policy key and determined, I here the policy key is: a2/home/index
If our cachedVary is not null, continue to execute:
 
for (int i = 0; i <= 2; i++) 
{ 
int num; 
string[] array = null; 
NameValueCollection serverVarsWithoutDemand = null; 
bool flag = false; 
switch (i) 
{ 
case 0: 
builder.Append("H"); 
array = cachedVary._headers; 
if (array != null) 
{ 
serverVarsWithoutDemand = request.GetServerVarsWithoutDemand(); 
} 
break; 
case 1: 
builder.Append("Q"); 
array = cachedVary._params; 
if (request.HasQueryString && ((array != null) || cachedVary._varyByAllParams)) 
{ 
serverVarsWithoutDemand = request.QueryString; 
flag = cachedVary._varyByAllParams; 
} 
break; 
default: 
builder.Append("F"); 
if (verb == HttpVerb.POST) 
{ 
array = cachedVary._params; 
if (request.HasForm && ((array != null) || cachedVary._varyByAllParams)) 
{ 
serverVarsWithoutDemand = request.Form; 
flag = cachedVary._varyByAllParams; 
} 
} 
break; 
} 
if (flag && (serverVarsWithoutDemand.Count > 0)) 
{ 
array = serverVarsWithoutDemand.AllKeys; 
num = array.Length - 1; 
while (num >= 0) 
{ 
if (array[num] != null) 
{ 
array[num] = CultureInfo.InvariantCulture.TextInfo.ToLower(array[num]); 
} 
num--; 
} 
Array.Sort(array, InvariantComparer.Default); 
} 
if (array != null) 
{ 
num = 0; 
int length = array.Length; 
while (num < length) 
{ 
string str = array[num]; 
if (serverVarsWithoutDemand == null) 
{ 
varyByCustomString = "+n+"; 
} 
else 
{ 
varyByCustomString = serverVarsWithoutDemand[str]; 
if (varyByCustomString == null) 
{ 
varyByCustomString = "+n+"; 
} 
} 
builder.Append("N"); 
builder.Append(str); 
builder.Append("V"); 
builder.Append(varyByCustomString); 
num++; 
} 
} 
} 

This code basically appends HQF3 characters to the key value, and the loop first processes the data from the server,
array = cachedVary._headers;
serverVarsWithoutDemand = request.GetServerVarsWithoutDemand();
The second is to process QueryString data:
array = cachedVary._params;
serverVarsWithoutDemand = request.QueryString;
Finally, Form data is processed
array = cachedVary._params;
serverVarsWithoutDemand = request.Form;
serverVarsWithoutDemand is the data of NameValueCollection type. Here, each key in serverVarsWithoutDemand is cycled, and the append string corresponding to each key is N+key+V+value. If value is null, the new value is assigned to "+n+". When QueryString and Form, the value of serverVarsWithoutDemand here is equal to
cachedVary._varyByAllParams, cachedVary is created in OutputCacheModule's OnLeave method:
vary = new CachedVary(varyByContentEncodings, varyByHeaders, varyByParams, varyByAllParams, currentSettings.VaryByCustom);
The value of varyByAllParams is as follows:
 
bool varyByAllParams = false; 
if (varyByParams != null) 
{ 
varyByAllParams = (varyByParams.Length == 1) && (varyByParams[0] == "*"); 
} 

It can be seen that varyByAllParams is basically false, and varyByAllParams is true only when varyByParams has and tightly has one element and is *, and serverVarsWithoutDemand is GetServerVarsWithoutDemand when varyByAllParams is false, which has nothing to do with our QueryString and Form3 methods. The GetServerVarsWithoutDemand() method may not be familiar to you, but let's look at its definition:
 
internal NameValueCollection GetServerVarsWithoutDemand() 
{ 
return this.GetServerVars(); 
} 

It doesn't matter if you don't know this method, we have an ServerVariables (get the collection of Web server variables) property similar to his:
 
public NameValueCollection ServerVariables 
{ 
get 
{ 
if (HttpRuntime.HasAspNetHostingPermission(AspNetHostingPermissionLevel.Low)) 
{ 
return this.GetServerVars(); 
} 
return this.GetServerVarsWithDemand(); 
} 
} 

The GetServerVarsWithDemand method also calls the GetServerVars method. Now we know the serverVarsWithoutDemand data.
C builder. Append (" "); Next, append the character C
Now it's time to handle the configuration of cache _varyByCustom
 
if (cachedVary._varyByCustom != null) 
{ 
builder.Append("N"); 
builder.Append(cachedVary._varyByCustom); 
builder.Append("V"); 
try 
{ 
varyByCustomString = context.ApplicationInstance.GetVaryByCustomString(context, cachedVary._varyByCustom); 
if (varyByCustomString == null) 
{ 
varyByCustomString = "+n+"; 
} 
} 
catch (Exception exception) 
{ 
varyByCustomString = "+e+"; 
HttpApplicationFactory.RaiseError(exception); 
} 
builder.Append(varyByCustomString); 
} 

This method is easy to understand, if _varyByCustom is not null then we append N+key+V+value. Where key is the _varyByCustom string, value is the value obtained by calling context.ApplicationInstance.GetVaryByCustomString (context, cachedVary.varyByCustom). If value is null, n+ builder.Append ("D");
 
if (((verb == HttpVerb.POST) && cachedVary._varyByAllParams) && (request.Form.Count == 0)) 
{ 
int contentLength = request.ContentLength; 
if ((contentLength > 0x3a98) || (contentLength < 0)) 
{ 
return null; 
} 
if (contentLength > 0) 
{ 
byte[] asByteArray = ((HttpInputStream) request.InputStream).GetAsByteArray(); 
if (asByteArray == null) 
{ 
return null; 
} 
varyByCustomString = Convert.ToBase64String(MachineKeySection.HashData(asByteArray, null, 0, asByteArray.Length)); 
builder.Append(varyByCustomString); 
} 
} 

This code mainly appends one character D to key, and then converts the content (bytes) of the request to Post (not form request.Form.Count == 0) to key after processing the request of Post (not form request.Form.Count == 0).
 
builder.Append("E"); 
string[] strArray2 = cachedVary._contentEncodings; 
if (strArray2 != null) 
{ 
string httpHeaderContentEncoding = context.Response.GetHttpHeaderContentEncoding(); 
if (httpHeaderContentEncoding != null) 
{ 
for (int j = 0; j < strArray2.Length; j++) 
{ 
if (strArray2[j] == httpHeaderContentEncoding) 
{ 
builder.Append(httpHeaderContentEncoding); 
break; 
} 
} 
} 
} 

This code first appends key with one character E, then the best ContentEncoding, ContentEncoding is context.Response.GetHttpHeaderContentEncoding () and the _contentEncodings in the cache policy is append.
So far we have covered the CreateOutputCachedItemKey method. The key of the caching policy has nothing to say about Http request method Get and Post, Request Path properties. But cache data about key objects:
(1) is related to our _headers, that is, the VaryByHeader attribute in the configuration. The value of VaryByHeader is different, while that of key is different
(2) related to _varyByAllParams, when it is true, it is actually related to request.QueryString, if the request is Post, it is also related to request.Form; _varyByAllParams is false by default, and true is also very simple. 1 varyByAllParams = (varyByParams.Length == 1) && (varyByParams[0] == "*")
(3) has to do with _varyByCustom, which appends the return value of the context.ApplicationInstance.GetVaryByCustomString (context, cachedVary._varyByCustom) method to key,
(4) relates to _contentEncodings, and if the value returned by context.Response.GetHttpHeaderContentEncoding () is appended to _contentEncodings.
Note: if this Http processing is 1 Post and request.Form.Count ==0&& _varyByAllParams is rue, then the sea area is related to the data from post.

Related articles: