Elaborate request[] and request.params[]
Read Catalogue
- Begin
- Review the original Blog
- Implementation approach Analysis
- More on Cookies
- Talk about NameValueCollection again.
- Talk about QueryString again, Form
- How to handle conflicts
- Request[] or request.params[]??
Today I'm going to talk about two collections that are easy to confuse: request[] and request.params[]
These two collections I mentioned them in my blog, "My idea of ASP. NET Core objects", and also gave an example of the difference in their form. But because there are more valuable objects to introduce in that blog, there is not much space to focus on these two collections. But I found that there were so many people who did not know the difference between the two sets, that I thought it was necessary to write a topic for them to elaborate on their differences.
In ASP, there are three more common sources of data from the client: QueryString, Form, Cookie. We can access these three objects in HttpRequest, for example, you can get some parameters contained in the URL from the querystring, you can get the form data from the form, you can get some session state and other user personalization parameter information from the cookie. In addition to these three major objects, HttpRequest also provides servervariables to let us get some of the variables from the Web server. Usually, these 4 data sources are very clear, I think no one will confuse them.
In general, if we can clearly know in advance which one of the parameters is from which set, then directly access the collection, the problem is simple. However, the more common data sources are usually only querystring, form, and especially when the client is using jquery's $.ajax () technology, can easily put the parameters into QueryString or form, then, The server is usually able to respond flexibly to this situation, using request[] and request.params[] Two ways to access these data from user submissions. The story of this article also produced: request[] and request.params[] What is the difference??
Back to top review blog original
Because "my idea of ASP. NET Core objects" have some introduction to them and examples, helpless, some people may for various reasons, did not see the text, here I have to post again:
These two properties allow us to easily "search" for 4 sets of QueryString, Form, Cookie or servervariables based on a key. Usually if the request is sent by the Get method, we generally access the QueryString to get the user's data, if the request is submitted using the Post method, we generally use form to access user-submitted form data. The use of Params,item allows us to write code without having to differentiate between get and post. The only difference between the two properties is that item accesses the 4 collections in turn, finds the result, and the params is accessed by merging data from 4 collections into a new collection (created when the collection does not exist) and then looking for the specified result.
To illustrate the differences more clearly, consider the following sample code:
<body> <p>item Result: <%= this. Itemvalue%></p> <p>params Result: <%= this. Paramsvalue%></p>
public partial class showitem:system.web.ui.page{ protected string itemvalue; protected string Paramsvalue; protected void Page_Load (object sender, EventArgs e) { string[] AllKeys = Request.QueryString.AllKeys; if (AllKeys. Length = = 0) Response.Redirect ("Showitem.aspx?name=abc", true); Itemvalue = request["name"]; Paramsvalue = request.params["name"];} }
Page is displayed in the browser before submission:
After clicking the Submit button, the browser displays:
The difference is obvious, I don't say much. Let me suggest that: Try not to use the params, not only the result of the above results of the judgment problem, there is no need to create a collection more, and worse is to write a cookie, will also update the collection.
As I said earlier, the objective reason: because there are more valuable objects in the blog to introduce, so there is not too much space to focus on these two collections. Now, let me tell you the difference in detail.
Back to top implementation mode analysisIn the previous example, I showed different results when accessing request[] and request.params[]. Why there are different results, I think we should go to see the Microsoft implementation in the. NET Framework.
First, let's take a look at the implementation of request[], which is a default indexer with the following implementation code:
public string this[string key]{ get { string str = this. Querystring[key]; if (str! = null) { return str; } str = this. Form[key]; if (str! = null) { return str; } HttpCookie cookie = this. Cookies[key]; if (cookie! = null) { return cookie. Value; } str = this. Servervariables[key]; if (str! = null) { return str; } return null;} }
This code means: According to the specified key, access to the Querystring,form,cookies,servervariables 4 sets, if found in any of the collection, immediately return.
Request.params[] is implemented as follows:
Public NameValueCollection params{ get { //if (httpruntime.hasaspnethostingpermission ( Aspnethostingpermissionlevel.low)) //{ // return this. Getparams (); } //return this. Getparamswithdemand (); For the sake of understanding, I commented the above code, in fact, the key is the following call. return this. Getparams (); }} Private NameValueCollection Getparams () { if (this._params = = null) { this._params = new Httpvaluecollection ( 0x40); This. Fillinparamscollection (); This._params. Makereadonly (); } return this._params;} private void Fillinparamscollection () { this._params. ADD (this. QueryString); This._params. ADD (this. Form); This._params. ADD (this. Cookies); This._params. ADD (this. ServerVariables);}
It is implemented by first judging if the _params field member is null, and if so, creating a collection and populating the data of the 4 collections of Querystring,form,cookies,servervariables. Future queries are made directly in this collection.
As we can see, this is two distinct implementations. That is why, in some special cases , accessing them will result in different results.
The difference is that: request.params[] Creates a new collection, merges the 4 data sources, and encounters a key with the same name, the natural result will be different.
Go back to the top and talk about cookies.In my blog, "My idea of ASP. NET Core objects," I said in a nutshell: and even worse, after the cookie is written, the collection is also updated. How to understand this sentence?
I think we should look at how we write a cookie and send it to the client. Here I will copy a section of "Coookie" in the original paragraph:
cookies are written to the browser : We can use the following code to write a cookie in the ASP and send it to the client's browser (for the sake of simplicity I have not set other properties).
HttpCookie cookie = new HttpCookie ("Mycookiename", "string value"); RESPONSE.COOKIES.ADD (cookie);
The key point of the code is to call RESPONSE.COOKIES.ADD () and let's see how they are implemented. First look at Response.Cookies.
Public httpcookiecollection cookies{ get { if (this._cookies = = null) { this._cookies = new HttpCookieCollection (this, false); } return this._cookies;} }
Then look at the implementation of this set of HttpCookieCollection:
public sealed class httpcookiecollection:nameobjectcollectionbase{public httpcookiecollection (): Base ( Stringcomparer.ordinalignorecase) { } internal HttpCookieCollection (httpresponse response, BOOL readOnly) : Base (stringcomparer.ordinalignorecase) { this._response = response; Base. IsReadOnly = readOnly; } public void Add (HttpCookie cookie) { if (this._response! = null) { this._response. Beforecookiecollectionchange (); } This. Addcookie (Cookie, true); if (this._response! = null) { this._response. Oncookieadd (cookie); } }
Note: When HttpCookieCollection is created in HttpResponse, the HttpResponse object is passed in, so when the Httpcookiecollection.add () method is called, the Will call HttpResponse's Oncookieadd (cookie); We went on to look at:
internal void Oncookieadd (HttpCookie cookie) {this . Request.addresponsecookie (cookie);}
Go to the Request object's call again, and then look at:
internal void Addresponsecookie (HttpCookie cookie) { if (this._cookies! = null) { this._cookies. Addcookie (Cookie, true); } if (this._params! = null) { this._params. Makereadwrite (); This._params. ADD (Cookie. Name, Cookie. Value); This._params. Makereadonly (); }}
From the above code analysis, we can see that when we call RESPONSE.COOKIES.ADD (), the cookie is added to the httprequest.cookies.
Also, if we access the process request.params[], it will be added to that set.
Go back to the top and talk about NameValueCollection.In the first example of this article, why code paramsvalue = request.params["name"]; The result is: "abc,123"?
According to the previous example code, we can tell that the value of ABC is provided by QueryString, 123 is provided by the form, and finally merged by Request.params[] to look like this. Has anyone ever thought: Why does it become this way together?
To answer this question, we need to review the definition of params:
Public NameValueCollection Params
Note: Its type is namevaluecollection. MSDN has a simple explanation for this collection:
This collection is based on the NameObjectCollectionBase class. However, unlike NameObjectCollectionBase, the class stores multiple string values under a key.
To make it easier for everyone to understand how this class works, I drew a sketch:
The "name" key corresponds to a ArrayList, and that ArrayList contains two strings: ABC and 123, which is how it works.
Now that it can store multiple strings under a key value, let's take a look at how it's actually implemented and go directly to the Add () method: (Note the comments I added in the code)
public virtual void Add (string name, String value) { if (base. IsReadOnly) { throw new NotSupportedException (SR.) GetString ("collectionreadonly")); } This. Invalidatecachedarrays (); This is a key call, it calls the base class, gets each name corresponding to the element, //and each name corresponding to the element is a ArrayList ArrayList list = (ArrayList) base. Baseget (name); if (list = = null) { //If no element of name exists, create ArrayList list = new ArrayList (1); if (value! = null) { //adds value to ArrayList, it will be the first value of list. ADD (value); } Base. Baseadd (name, list); } else if (value = null) { //continues to add a new value in the original ArrayList list. ADD (value);} }
Let's take a look at how the. NET Framework is implemented when we visit the params[] Indexer:
public string this[string name]{ get {return this. Get (name); } set {this. Set (name, value); }}public Virtual string Get (string name) { //ArrayList ArrayList list = (ArrayList) base based on name. Baseget (name); Turn ArrayList into a string line return getasonestring (list);} private static string getasonestring (ArrayList list) { int num = (list = null)? list. count:0; if (num = = 1) { return (string) list[0]; } if (num <= 1) { return null; } StringBuilder builder = new StringBuilder ((string) list[0]); for (int i = 1; i < num; i++) { Builder. Append (', '); This is where the comma comes from. Builder. Append (String) list[i]); } Return builder. ToString ();}
Now, you should understand why it is separated by commas when a key has multiple values.
Perhaps, see here, you have a new idea: for the case of multiple values, but also I have to split them by commas, too much trouble, there is no way to split it?
The answer is: Yes, you can access the GetValues method of NameValueCollection, the implementation of this method is as follows:
Public virtual string[] GetValues (string name) { ArrayList list = (ArrayList) base. Baseget (name); return Getasstringarray (list);} private static string[] Getasstringarray (ArrayList list) { int count = (list = null)? list. count:0; if (count = = 0) { return null; } string[] array = new String[count]; List. CopyTo (0, array, 0, count); return array;}
I think the result must be what you expect, it is a string[], we can easily traverse it:
string[] Array = Request.Params.GetValues ("name"); if (array! = null) foreach (string val in array)
Go back to the top and talk about QueryString, FormI explained the working principle of NameValueCollection and revealed the request.params["name"; The reason for the result of "abc,123".
In fact, this bizarre result is sometimes not just a params, the same story may be QueryString, the form of the two objects (which will eventually be reflected in the request[] there.
I'll take an example of "My idea of an ASP. NET Core object" to illustrate it:
protected void Page_Load (object sender, EventArgs e) { string[] AllKeys = Request.QueryString.AllKeys; if (AllKeys. Length = = 0) Response.Redirect ( request.rawurl + "? aa=1&bb=2&cc=3&aa=" + Httputility.urlencode (" 5,6,7 "), true); StringBuilder sb = new StringBuilder (); foreach (string key in AllKeys) sb. AppendFormat ("{0} = {1}<br/>", httputility.htmlencode (key), Httputility.htmlencode (request.querystring[ Key])); This.labResult.Text = sb. ToString ();}
The final results of the page display are as follows ( note the result of a key value of AA ):
In the sample code, the Start section is used to check if the URL contains parameters, and if not, add some parameters. The reason for this is that the first time you visit this page, the URL must not contain parameters, in order to be able to demonstrate, so I added some fixed parameters, so as to facilitate the subsequent explanation.
This example also demonstrates: encounter multiple values with the same name, separated by commas, not the params, QueryString may have, of course, the form can not escape the entanglement of this feature, but I would like to give a useful example.
I have such an input interface (left), and hope that the final input results are shown in the right image:
I think the implementation of this feature is not difficult, but how to do it is the simplest?
Below I put out my implementation method, we look at the calculation is not quite easy:
<TR><TD style= "Vertical-align:top" > Project type </td><td> <% foreach (String pt in Apphelper.projecttypes) {%> <label><input type= "checkbox" Name= "ProjectType" value= "<%= pt%>" /><%= pt%></label><br/> <%}%> </td></tr>
Note: The name of all checkboxes is the same.
Service side Well, I think there is no need to post the code, I think you understand.
In this example, I just took advantage of this feature of NameValueCollection, let it help me achieve this comma-separated effect, otherwise, I have to do it myself!
Back to top how to handle conflictsWith some of the previous examples, we can see that not only params[] will have a conflict, as long as the type is NameValueCollection data source, there is this problem.
I would like to reiterate:QueryString, Form,param have such a conflict problem, but Param need to merge 4 kinds of data sources, it will be the odds of the conflict become larger.
So how do we handle this kind of conflict correctly? Remember the NameValueCollection getvalues method I mentioned earlier, and I had to use it. (unless you want to split the string yourself manually) and then use a loop to access all conflicting values, like this:
string[] Array = Request.Params.GetValues ("name"); if (array! = null) foreach (string val in array)
Note: The return result of request[] is a string, and you cannot use this method. However, it has a much less chance of conflict.
Now, there is a real problem: QueryString, form is the most commonly used data source, do we want to deal with it this way?
This is really a real problem, and I think before answering this question, we need to analyze what it looks like when a key conflict occurs in these two sets.
1. "Abc.aspx?id=1 &id=2" in this URL, I would like to ask you: see this URL, what would you think? I think it's wrong and wrong in the operation of stitching the URL. Secondly, I think that the modification or splicing of the URL is usually controlled by a tool class, we have reason to ensure that it will not conflict, after all, the scope is correspondingly small, we are easy to give this guarantee. Therefore, I think that direct access to QueryString can ignore the possibility of this conflict.
2. Duplicate name in the form data. I think there is a possibility of conflict in this set, but it is also very likely that we have deliberately arranged it, as in the previous example. Secondly, the content of the form is relatively fixed in the development phase, the name of each input control is also relatively clear, there is no possibility of dynamic transformation, so I think, direct access to the form can also ignore the possibility of this conflict.
On the other hand, we usually write querystring[], form[] are too accustomed to, such code too much, it is impossible to change the judgment of the cycle, therefore, we can only try to ensure that within a data source range, they are not duplicated. In fact, the first two collections are usually only related to one page, and the range is relatively small and easier to guarantee. Therefore, if you have this assurance, it is acceptable to ignore the conflict when accessing these two-class collections.
However, the params needs to merge 4 kinds of data sources, especially the two classes of objects containing cookies,servervariables are not related to a page, they are global, so the likelihood of a conflict is greater, so I think: If you want to access params[], then, Please change to params.getvalues (), because it will be more appropriate.
Back to the top request[] or request.params[]??Before saying so much, I think request[] and request.params[] difference, this time should be clear, to this also give a conclusion: in the end choose request[] or request.params[]??
I think a lot of people should be more concerned about this answer, here I would like to talk about my point of view, but I would like to say: all of the text in this article, only to express my personal views, for reference only.
I think: To answer this question clearly, it is necessary to observe the two from two angles: common usage and design reasons.
1. Common usage: I have always thought that the design of these two sets is for convenience, so that we can not distinguish between get, post and directly get the required user data. If we do not have these two sets, and we need not distinguish get,post, it is obviously necessary to implement this kind of collection, and in their own implementation, it is very likely to first try to access QueryString, if not, then to find the form .... See, this is not the way to achieve request[]? It is also based on this premise that when encountering the previous "abc,123" scenario, the results of request[] may be more in line with our expectations. After all, after obtaining the results, we will make some judgments based on the results, such as: the name parameter may correspond to a database table field, it can find an actual data row, if the result is ABC or 123, then the program can handle (all have matching records), but to a "abc,123", This is really not going to work out.
On the other hand, in the previous example, I also explained that this is not params[] unique, QueryString, form all have this problem, naturally request[] also have this problem, just because the params need to merge 4 kinds of data source, let this The chances of a conflict are even greater.
Here, it is necessary to talk about the previous examples, "abc,123", name in the QueryString, form repeating, obviously this is unreasonable design, in reality, should not produce such things, unless by accident. However, when the occasional misfortune occurs, it can also reflect the difference between the two. As for some of the examples I have mentioned earlier, although it is unlikely to happen in the real world, my intention is to show you the details of these techniques and to show some of the things that might happen by chance, so please don't think that's a technical misleading.
2. Design reasons: Let us again from the angle of design rigor to see the difference between the two, or take "abc,123" This example, request[] this way of judging, obviously will omit some information, therefore, from the point of view of rigor, request[] is imperfect. After all, how will end users use these two APIs in an idea that no one knows. Microsoft is the design platform, they have to consider this problem, do not design these two sets, is the. NET Framework is imperfect, wrong, is our own fault.
Based on the above, I give my 4 points of view:
1. It is not recommended to use params[] because: A. Do not want to be affected by accidental circumstances, B. Higher cost of use.
2. request[] Simple to use, suitable for applications where the requirements are not high: sample code.
3. If you need to balance performance and ease of use, you can imitate request[] design yourself. (usually does not require access to 4 collections)
4. Understand the differences, experience the details, and sometimes find that it is valuable to use.
Elaborate request[] and request.params[]