In the previous article we have implemented a custom resource file access, which we use it with Modelmetadata to achieve autonomous access to resource files. This is done to make it easier for us to use the resource file in the native way of MVC. Since my article aims to document the implementation of the MVC project, I do not explain the underlying implementation of the framework (in fact, considering their own ability, can not explain how deep. For a deeper understanding of MVC's underlying implementation, search by yourself. Here I recommend Jing Jinnan (Artech) Teacher's related blog post).
For the use of EF, we have to know System.ComponentModel.DataAnnotations. DataAnnotations defines a series of attribute for our attribute field annotation scheme. For example, Displayattribue, which defines the text information for the name displayed by the property. RequiredAttribute is used to define whether a property is required, and the prompt message after a required check fails. They are among the two of our most commonly used annotation attributes, and we generally use them to describe how our fields are displayed in the user interface. For example, we introduce the following attribute on the username attribute defined by UserProfile:
1 1 )]2 "TheUser Name is required! " )][3 "filed:user Name")]4 Public string Get set; }
View Code
The field is displayed in the Edituser.cshtml view as follows:
1 @using (Html.BeginForm ("Edituser", "account", FormMethod.Post))2 {3 <P>@Html. Labelfor (P=>p.username)</P> 4 <P>@Html. Textboxfor (P=>p.username)</P>5 6 <inputtype= "Submit"value= "Submit" />7}
View Code
Run the project and open the page, click the Submit button directly, you will get the following display effect:
This shows that the MVC framework has helped us print the UI display information for field registration to the current page. However, the resource language of our project itself is undecided, or, in the need of multi-lingual support, this scheme is somewhat farfetched. Although System.ComponentModel.DataAnnotations already provides definitions for using custom resources, they are either for. resx or for resource classes that have already been compiled. We cannot use our custom XML resource files. For this we have two options to transform it to use our custom resource files. They are: Custom Custmordisplayattribute to transform the MVC framework. The first scenario is used in the same way as the example above, except that we need to introduce a custom attribute comment for each field that needs to be displayed on the page. The latter two are more convenient and do not require any changes to the type definition. Here, we don't discuss the first scenario.
The second scenario belongs to the "advanced scenario", which means that the problem is addressed at the design level.
For this scenario, we first need to understand modelmetadata, and Modelmetadataprovider. Only the relevant code is attached here, not in-depth discussion.
The first is to define our own modelmetadataprovider.
1 Public classAppmodelmetadataprovider:cacheddataannotationsmodelmetadataprovider2 {3 protected OverrideCacheddataannotationsmodelmetadata Createmetadatafromprototype (cacheddataannotationsmodelmetadata prototype, Func <Object>modelaccessor)4 {5Cacheddataannotationsmodelmetadata metadata =Base. Createmetadatafromprototype (prototype, modelaccessor);6 if(metadata. Containertype! =NULL&&!string.isnullorempty (metadata. PropertyName))7 {8Metadata. DisplayName = Resource.getdisplay (string. Format ("{0}. {1}", metadata. Containertype.name, metadata. PropertyName));9 }Ten returnmetadata; One } A}
View Code
We have only rewritten the Createmetadatafromprototype method in the Cacheddataannotationsmodelmetadataprovider type, which, in this method, We will model (the model here is not just a strongly typed page definition, it can also be a strongly typed property.) When the page is initialized, you need to get the model type of the current page. Therefore, the model at this time is a strongly typed instance of page binding, and its containertype is empty. However, when the page accesses properties of this type, such as P = = P.username, the model at this time is Username,containertype the DisplayName property of the strongly typed page binding). Originally DisplayName would return the resource content defined in the DisplayAttribute comment for the property, and now we'll modify it to get the content from the custom resource file ( Note: The resource's key is defined strictly according to "container type name. Property name" ).
Finally, add code in the Application_Start () of the global file to use our custom provider.
1 protected voidApplication_Start ()2 {3 Arearegistration.registerallareas ();4 5 Webapiconfig.register (globalconfiguration.configuration);6 filterconfig.registerglobalfilters (globalfilters.filters);7 routeconfig.registerroutes (routetable.routes);8 bundleconfig.registerbundles (bundletable.bundles);9 Authconfig.registerauth (); Ten OneBootstrapper.initialise ();//initializing the IOC container A -Modelmetadataproviders.current =NewAppmodelmetadataprovider (); -}
View Code
In the view file, we modified the HtmlHelper to display the field names using MVC's custom. As follows:
1@using (Html.BeginForm ("Edituser"," Account", FormMethod.Post))2 {3 @Html. ValidationSummary ()4<div>5@Html. labelfor (P =p.username)6@Html. textboxfor (P =p.username)7</div>8<input type="Submit"Value="Submit"/>9}
View Code
The second scenario is complete. Run the project and look at our page changes. Then modify the contents of the resource file, and the changes to the resource file can be applied immediately without recompiling.
We then add an address type attribute to the UserProfile type definition.
1[Table ("UserProfile")]2 Public classUserProfile3 {4 //irrelevant code omitted ...5 6 Public int? Addressid {Get;Set; }7 8[ForeignKey ("Addressid")]9 PublicAddress Address {Get;Set; }Ten } One A[Table ("Address")] - Public classaddress:baseentity<int> - { the Public stringCity {Get;Set; } -}
View Code
Modify the Edituser view as follows:
1@using (Html.BeginForm ("Edituser"," Account", FormMethod.Post))2 {3 @Html. ValidationSummary ()4<div>5@Html. labelfor (P =p.username)6@Html. textboxfor (P =p.username)7@Html. labelfor (P =p.address.city)8@Html. textboxfor (P =p.address.city)9</div>Ten<input type="Submit"Value="Submit"/> One}
View Code
In the resource file, add
1 <resource key="address.city" value="City" />
Then when you run the Project open page, you can see the following effect:
Custom resource information for navigation properties is also displayed. Here you can see that the Containertype in provider is the actual type of Address when p = = p.address.city, and the model in Modelmetadata is the property of the subtype that is actually being displayed.
Problem:
We make use of custom resources by modifying the properties within the Modelmetadata. This is a high-level application and it is necessary to have a deep understanding of MVC's model binding knowledge. I spent a considerable amount of time in completing this article (roughly 3 days in rough statistics). The main problem is to resolve multiple properties of the same type to display different custom resources. For example, define two attributes of the same address type in the UserProfile type, useraddress, and companyaddress, respectively. If the city name of both properties is displayed on the page at the same time, the display is the same, pointing to the same resource:
<resource key= "address.city" value= "City"/>. However, it was not always possible to find a suitable solution under the second scenario. Hope to have the talent for the next doubts, greatly appreciated!!!
Next Issue preview: The third scenario addresses the same type of navigation properties that display different custom resources.
. NET MVC4 Training Record VI (using MODELMETADATA for autonomous access to resources)