ASP. net mvc provides the system with ValueProvider as the core value: NameValueCollectionValue

Source: Internet
Author: User

During Model binding, You need to extract the corresponding data from the request data according to the binding context based on the Action method parameters to provide the corresponding data. Specifically, the data bound to the Model has multiple sources, which may come from the form or JSON string of the Post, or from the current route data, or from the plug-in string of the request address. ASP. net mvc implements this data acquisition/provision mechanism based on different data sources in a component called ValueProvider.
Directory
I. IValueProvider and ValueProviderResult
Ii. NameValueCollectionValueProvider
3. Two prefix forms
4. Example: return the Key with the specified prefix
V. FormValueProvider and QueryStringValueProvider
I. IValueProvider and ValueProviderResult
Generally, the data source used by a ValueProvider is a dictionary-type data structure. We can use it to obtain a value that matches the Key with the current binding context. ValueProvider implements the IValueProvider interface with the following definitions. The GetValue method obtains the corresponding value object from the data source based on the specified Key, which is based on the current binding context. This Key may not be exactly the same as the Key of the corresponding data entry in the data source, and the latter may add the corresponding prefix based on the former, the ContainsPrefix method is used to determine whether the Key of the data source dictionary has a specified prefix.
1: public interface IValueProvider
2 :{
3: bool ContainsPrefix (string prefix );
4: ValueProviderResult GetValue (string key );
5 :}
The GetValue of IValueProvider returns a ValueProviderResult object. we can regard ValueProviderResult as an encapsulation of the ValueProvider object. As shown in the following code snippet, ValueProviderResult has three read-only attributes, and RawValue indicates the original value object. AttemptedValue indicates a string of a value object. This attribute is mainly used for display.
1: [Serializable]
2: public class ValueProviderResult
3 :{
4: public ValueProviderResult (object rawValue, string attemptedValue, CultureInfo culture );
5: public object Convertor (Type type );
6: public virtual object Convertor (Type type, CultureInfo culture );
7:
8: public string AttemptedValue {get ;}
9: public CultureInfo Culture {get ;}
10: public object RawValue {get ;}
11 :}
ValueProviderResult provides two convertor methods to achieve conversion to the specified target type. Some types of formatting behaviors depend on the corresponding language Culture (such as time, date, and currency), and the Language and Culture Information of this auxiliary format lake is represented by the Culture attribute. The first ValueProviderResult method reloads the type conversion using the language Culture represented by the attribute Culture.
Ii. NameValueCollectionValueProvider
As mentioned above, the Model data source generally has a dictionary-like structure, while the NameValueCollection can be represented as a dictionary where the Key is not unique, the ValueProvider that uses the NameValueCollection object as the data source is represented by the NameValueCollectionValueProvider type defined below. The NameValueCollection object of the data source is specified in the constructor. Another CultureInfo parameter of the constructor indicates the language and culture information that is used for data conversion.
1: public class NameValueCollectionValueProvider: IUnvalidatedValueProvider, IEnumerableValueProvider, IValueProvider
2 :{
3: // other members
4: public NameValueCollectionValueProvider (NameValueCollection collection, CultureInfo culture );
5:
6: public virtual bool ContainsPrefix (string prefix );
7: public virtual IDictionary <string, string> GetKeysFromPrefix (string prefix );
8: public virtual ValueProviderResult GetValue (string key );
9: public virtual ValueProviderResult GetValue (string key, bool skipValidation );
10 :}
11:
12: public interface IEnumerableValueProvider: IValueProvider
13 :{
14: IDictionary <string, string> GetKeysFromPrefix (string prefix );
15 :}
16:
17: public interface IUnvalidatedValueProvider: IValueProvider
18 :{
19: ValueProviderResult GetValue (string key, bool skipValidation );
20 :}
From the code snippet above, we can see that in addition to the IValueProvider interface, NameValueCollectionValueProvider also implements the IEnumerableValueProvider and IUnvalidatedValueProvider interfaces. As the name suggests, IEnumerableValueProvider is mainly used to provide data for a set of target types. The GetKeysFromPrefix method returns the Key with the specified prefix in a dictionary. By default, data is verified when data is provided. The IUnvalidatedValueProvider interface provides an additional GetValue method that allows us to ignore data verification.
3. Two prefix forms
The data provision mechanism that assists in Model binding is based on the Model metadata. Through the first knowledge of the Model metadata, we know that the Model metadata used to describe a complex data type has a hierarchical tree structure, nameValueCollection, as a data source, is a "flat" structure. The prefix is used to match the two data sources. For example, if the target type of an object provided through NameValueCollectionValueProvider is Contact with the following definitions. The attribute of the Contact Address is a complex type of Address. Therefore, the Model metadata tree of the Contact type has two levels.
1: public class Contact
2 :{
3: public string Name {get; set ;}
4: public string PhoneNo {get; set ;}
5: public string EmailAddress {get; set ;}
6: public Address {get; set ;}
7 :}
8: public class Address
9 :{
10: public string Province {get; set ;}
11: public string City {get; set ;}
12: public string District {get; set ;}
13: public string Street {get; set ;}
14 :}
Since each metadata value in NameValueCollection is a string, it is impossible to represent a complex type separately. A complex type object needs to be assembled by multiple element values. If you use NameValueCollectionValueProvider to initialize a complete Contact object, it means that the NameValueCollection of the data source must contain at least seven elements, respectively targeting the three attribute values of the Contact attribute except the Address attribute and the four attribute values as addresses, the two types of elements are distinguished by attribute prefix in NameValueCollection. The specific structure is as follows.
1: Name: Foo
2: PhoneNo: 123456789
3: EmailAddress: Foomail.com
4: Address. Province: Jiangsu
5: Address. City: Suzhou
6: Address. District: Industrial Park
7: Address. Street: No. 328 xinghu Street
Using periods (.) as the delimiter prefix can not only represent attribute-based hierarchical relationships, but also be used for data filtering. As shown in the following code snippet, we define an AddContacts for adding a Contact in ContactController. It has two Contact type parameters foo and bar, which indicate two different contacts to be added.
1: public class ContactController
2 :{
3: public void AddContacts (Contact foo, Contact bar)
4 :{
5: // omitted implementation
6 :}
7 :}
If we use NameValueCollectionValueProvider to provide two Contact objects as parameters of the AddContacts method, the data elements stored in NameValueCollection must be properly mapped with them. Generally, this can be achieved through the prefix of the parameter name. The specific data structure is as follows.
1: foo. Name: Foo
2: foo. PhoneNo: 123456789
3: foo. EmailAddress: Foo@gmail.com
4: foo. Address. Province: Jiangsu
5: foo. Address. City: Suzhou
6: foo. Address. District: Industrial Park
7: foo. Address. Street: No. 328 xinghu Street
8:
9: bar. Name: Bar
10: bar. PhoneNo: 987654321
11: bar. EmailAddress: Bar@gmail.com
12: bar. Address. Province: Jiangsu
13: bar. Address. City: Suzhou
14: bar. Address. District: Industrial Park
15: bar. Address. Street: No. 328 Airport Road
In addition to in addition to the "prefix", Data Source Elements of the array or set type can use the "Index" prefix. Such prefix is represented by square brackets, the following data structure can represent the Contact array or set containing two elements.
1: [0]. Name: Foo
2: [0]. php: 123456789
3: [0]. EmailAddress: Foo@gmail.com
4 :...
5: [1]. Name: Bar
6: [1]. php: 987654321
7: [1]. EmailAddress: Bar@gmail.com
8 :...
9:
In addition to using numbers as indexes, we can also use text as indexes in the following ways. The Model binding mechanism for two different types of indexes is different, which will be described later.
1: [foo]. Name: Foo
2: [foo]. php: 123456789
3: [foo]. EmailAddress: Foo@gmail.com
4 :...
5: [bar]. Name: Bar
6: [bar]. PhoneNo: 987654321
7: [bar]. EmailAddress: Bar@gmail.com
8 :...
If the data source elements are differentiated for different target set objects, the corresponding prefix is also required. The data structure of the phase surface can be viewed as a data source for two Contact lists (first and second.
1: first [0]. Name: Zhao
2: first [0]. PhoneNo: 12
3: first [0]. EmailAddress: zhao @ gmail.com
4 :...
5: first [1]. Name: Qian
6: first [1]. PhoneNo: 34
7: first [1]. EmailAddress: qian@gmail.com
8 :...
9:
10: second [0]. Name: Sun
11: second [0]. PhoneNo: 56
12: second [0]. EmailAddress: sun@gmail.com
13 :...
14: second [1]. Name: Li
15: second [1]. PhoneNo: 78
16: second [1]. EmailAddress: li@gmail.com

4. Example: return the Key with the specified prefix
After learning about two different types of prefixes, let's take a look at the GetKeysFromPrefix method implemented by NameValueCollectionValueProvider. The definition of this method shows that it returns an IDictionary <string, string> object, but what data does this object have? Here is an example. In an empty Web application created using the ASP. net mvc Project template of Visual Studio, we define the next default HomeController. In the Action method Index, we create a NameValueCollection object and create a NameValueCollectionValueProvider for it.
1: public class HomeController: Controller
2 :{
3: public void Index ()
4 :{
5: NameValueCollection datasource = new NameValueCollection ();
6: datasource. Add ("foo. Name", "Foo ");
7: datasource. Add ("foo. PhoneNo", "123456789 ");
8: datasource. Add ("foo. EmailAddress", "Foo@gmail.com ");
9: datasource. Add ("foo. Address. Province", "Jiangsu ");
10: datasource. Add ("foo. Address. City", "Suzhou ");
11: datasource. Add ("foo. Address. District", "Industrial Park ");
12: datasource. Add ("foo. Address. Street", "328 xinghu Street ");
13: NameValueCollectionValueProvider valueProvider = new NameValueCollectionValueProvider (datasource, CultureInfo. InvariantCulture );
14:
15: var keyDictionary = valueProvider. GetKeysFromPrefix ("foo ");
16: Response. Write ("foo <br/> ");
17: foreach (var item in keyDictionary)
18 :{
19: Response. Write (string. Format ("{0 }:{ 1} <br/>", item. Key, item. Value ));
20 :}
21:
22: keyDictionary = valueProvider. GetKeysFromPrefix ("foo. Address ");
23: Response. Write ("<br/> foo. Address <br/> ");
24: foreach (var item in keyDictionary)
25 :{
26: Response. Write (string. Format ("{0 }:{ 1} <br/>", item. Key, item. Value ));
27 :}
28 :}
29 :}
The code snippet above shows that the data element used as NameValueCollectionValueProvider is added according to the attribute definition of the Contact type. The keys prefixed with "foo" and "foo. Address" are returned. After running the program, the following output is displayed in the browser. We can see that for dictionary objects returned with a specified prefix, the Key and Value are different because the former does not contain the specified prefix while the latter does. In addition, all the elements in the dictionary object are at the same level. When "foo" is specified as the prefix, the returned elements are for the four attributes of Contact. Although NameValueCollection does not contain an element named "foo. Address", it is still used as the Key prefixed with "foo.
1: foo
2: Name: foo. Name
3: PhoneNo: foo. PhoneNo
4: EmailAddress: foo. EmailAddress
5: Address: foo. Address
6:
7: foo. Address
8: Province: foo. Address. Province
9: City: foo. Address. City
10: District: foo. Address. District
11: Street: foo. Address. Street
Next, we will use the corresponding method to demonstrate the Index-based prefix. Therefore, we have rewritten the Index inversion method of HomeController as follows. The NameValueCollection object as the data source targets a Contact set containing two elements. The prefix "first" can be used as the name of the collection object.
1: public class HomeController: Controller
2 :{
3: public void Index ()
4 :{
5: NameValueCollection datasource = new NameValueCollection ();
6: datasource. Add ("first [0]. Name", "Foo ");
7: datasource. Add ("first [0]. PhoneNo", "123456789 ");
8: datasource. Add ("first [0]. EmailAddress", "Foo@gmail.com ");
9:
10: datasource. Add ("first [1]. Name", "Bar ");
11: datasource. Add ("first [1]. PhoneNo", "987654321 ");
12: datasource. Add ("first [1]. EmailAddress", "Bar@gmail.com ");
13: NameValueCollectionValueProvider valueProvider = new NameValueCollectionValueProvider (datasource, CultureInfo. InvariantCulture );
14:
15: var keyDictionary = valueProvider. GetKeysFromPrefix ("first ");
16: Response. Write ("first <br/> ");
17: foreach (var item in keyDictionary)
18 :{
19: Response. Write (string. Format ("{0 }:{ 1} <br/>", item. Key, item. Value ));
20 :}
21:
22: keyDictionary = valueProvider. GetKeysFromPrefix ("first [0]");
23: Response. Write ("<br/> first [0] <br/> ");
24: foreach (var item in keyDictionary)
25 :{
26: Response. Write (string. Format ("{0 }:{ 1} <br/>", item. Key, item. Value ));
27 :}
28:
29: keyDictionary = valueProvider. GetKeysFromPrefix ("first [1]");
30: Response. Write ("<br/> first [1] <br/> ");
31: foreach (var item in keyDictionary)
32 :{
33: Response. Write (string. Format ("{0 }:{ 1} <br/>", item. Key, item. Value ));
34 :}
35 :}
36 :}
We obtain the dictionary objects for the three Prefixes "first", "first [0]", and "first [1]" and present their keys and values. After the program is executed, the following output will be generated in the browser, if we regard "[" and "]" As and ". "The same delimiter, GetKeysFromPrefix rules for the index as the prefix and based on". there is no essential difference between prefix rules.
1: first
2: 0: first [0]
3: 1: first [1]
4:
5: first [0]
6: Name: first [0]. Name
7: PhoneNo: first [0]. PhoneNo
8: EmailAddress: first [0]. EmailAddress
9:
10: first [1]
11: Name: first [1]. Name
12: PhoneNo: first [1]. PhoneNo
13: EmailAddress: first [1]. EmailAddress

V. FormValueProvider and QueryStringValueProvider
In the ASP. net mvc application programming interface, NameValueCollectionValueProvider has two successors: FormValueProvider and QueryStringValueProvider. For FormValueProvider, The NameValueCollection object as the data source is created through the request form. Name and Value are derived from the Name and Value of the form element, respectively, its definition can basically be represented by the following code (the actual definition is different ).
1: public sealed class FormValueProvider: NameValueCollectionValueProvider
2 :{
3: public FormValueProvider (ControllerContext controllerContext)
4: base (controllerContext. RequestContext. HttpContext. Request. Form, CultureInfo. CurrentCulture)
5 :{}
6 :}
For QueryStringValueProvider, it is needless to say that as the NameValueCollection object of the data source, the NameValueCollection object naturally comes from the query string of the request. Its definition can basically be expressed through the following code (the actual definition is different ).
1: public sealed class QueryStringValueProvider: NameValueCollectionValueProvider
2 :{
3: public NameValueCollection (ControllerContext controllerContext)
4: base (controllerContext. RequestContext. HttpContext. Request. QueryString, CultureInfo. CurrentCulture)
5 :{}
6 :}

 

 

Author: Artech

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.