.NET MVC4 实训记录之六(利用ModelMetadata实现资源的自主访问)

时间:2023-03-09 01:45:47
.NET MVC4 实训记录之六(利用ModelMetadata实现资源的自主访问)

  上一篇我们已经实现自定义资源文件的访问,该篇我们使用它配合ModelMetadata实现资源文件的自主访问。这样做是为了我们能更简单的用MVC原生的方式使用资源文件。由于我的文章旨在记录MVC项目的实现,因此不做框架底层实现方面的讲解(其实考虑到自己的能力,也不能为大家讲解的多么深入。如需要更深入的了解MVC底层实现,请自行搜索。在这里我推荐蒋金楠(Artech)老师的相关博文)。

  对于使用EF,我们不得不知道System.ComponentModel.DataAnnotations。DataAnnotations下定义了一系列的Attribute,用于我们的属性字段注解方案。例如DisplayAttribue,用于定义属性所显示的名称的文本信息。RequiredAttribute用于定义属性是否必填,以及必填校验失败后的提示信息。它们是我们最常用的注解属性中的两个,我们一般都使用它们来描述我们的字段在用户界面的显示效果。例如我们在UserProfile定义的UserName属性上引入如下Attribute:

         [Column(Order = )]
[Required(ErrorMessage = "The User Name is required!")]
[Display(Name = "Filed: User Name")]
public string UserName { get; set; }

  在EditUser.cshtml视图中已如下方式显示该字段:

 @using (Html.BeginForm("EditUser", "Account", FormMethod.Post))
{
<p>@Html.LabelFor(p=>p.UserName)</p>
<p>@Html.TextBoxFor(p=>p.UserName)</p> <input type="submit" value="提交" />
}

  运行项目并打开该页面,直接点击提交按钮,会得到如下的显示效果:

aaarticlea/png;base64,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" alt="" />

  这说明MVC框架已经帮我们将字段注册的UI显示信息打印到当前页面。 可是,我们的项目本身的资源语言未定,或者说,需要多语言支持,这个方案就有些牵强。虽然System.ComponentModel.DataAnnotations已经提供了使用自定义资源的相关定义,但都是针对.resx或者已经进行编译过的资源类。无法使用我们自定义的XML资源文件。对此我们有两种方案对其进行改造,以使用我们自定义的资源文件。它们分别是:自定义CustmorDisplayAttribute,改造MVC框架。第一个方案的使用方式与上面例子相同,只不过我们需要为每个需要显示在页面上的Field都引入自定义的属性注释。后两者则更加便捷,无需对类型定义做出任何改变。在这里,我们不讨论第一种方案。

  第二种方案属于“高级方案”,也就是说从设计层面解决这个问题。

  针对这种方案,我们先要了解ModelMetadata,以及ModelMetadataProvider。在此仅附上相关的代码,不做深入讨论。

  首先,是要定义我们自己的ModelMetadataProvider。

     public class AppModelMetadataProvider : CachedDataAnnotationsModelMetadataProvider
{
protected override CachedDataAnnotationsModelMetadata CreateMetadataFromPrototype(CachedDataAnnotationsModelMetadata prototype, Func<object> modelAccessor)
{
CachedDataAnnotationsModelMetadata metadata = base.CreateMetadataFromPrototype(prototype, modelAccessor);
if (metadata.ContainerType != null && !String.IsNullOrEmpty(metadata.PropertyName))
{
metadata.DisplayName = Resource.GetDisplay(string.Format("{0}.{1}", metadata.ContainerType.Name, metadata.PropertyName));
}
return metadata;
}
}

  我们仅重写了CachedDataAnnotationsModelMetadataProvider类型中的CreateMetadataFromPrototype方法,在该方法中,我们将Model(这里的Model并非只是页面定义的强类型,它也可以是强类型的属性。当页面初始化阶段,需要获取当前页面的模型类型。因此,这个时候的Model就是页面绑定的强类型实例,其ContainerType为空。但当页面访问到此类型的属性,例如 p => p.UserName,此时的Model就是UserName,ContainerType则为页面绑定的强类型)的DisplayName属性进行修改。原本DisplayName会返回属性的DisplayAttribute注释中定义的资源内容,现在我们将其修改为从自定义资源文件中获取内容(注意:资源的键要严格按照“容器类型名.属性名”进行定义)。

  最后,在Global文件的Application_Start()中添加代码以使用我们自定义的Provider。

     protected void Application_Start()
{
AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth(); Bootstrapper.Initialise(); //初始化IOC容器 ModelMetadataProviders.Current = new AppModelMetadataProvider();
}

  在视图文件中,我们修改成利用MVC自定义的HtmlHelper显示字段名。如下:

 @using (Html.BeginForm("EditUser", "Account", FormMethod.Post))
{
@Html.ValidationSummary()
<div>
@Html.LabelFor(p => p.UserName)
@Html.TextBoxFor(p => p.UserName)
</div>
<input type="submit" value="提交" />
}

  第二种方案已完成。运行项目,观察一下我们的页面变化。然后修改一下资源文件中的内容,资源文件的修改也能被立刻应用,而不需要重新编译。

  然后我们在UserProfile类型定义中添加一个Address类型的属性。

     [Table("UserProfile")]
public class UserProfile
{
//无关代码省略...... public int? AddressId { get; set; } [ForeignKey("AddressId")]
public Address Address { get; set; }
} [Table("Address")]
public class Address: BaseEntity<int>
{
public string City { get; set; }
}

  修改EditUser视图,如下:

 @using (Html.BeginForm("EditUser", "Account", FormMethod.Post))
{
@Html.ValidationSummary()
<div>
@Html.LabelFor(p => p.UserName)
@Html.TextBoxFor(p => p.UserName)
@Html.LabelFor(p => p.Address.City)
@Html.TextBoxFor(p => p.Address.City)
</div>
<input type="submit" value="提交" />
}

  在资源文件中添加

 <resource key="Address.City" value="City"/>

  那么运行项目打开页面后,可以看到如下效果:

  aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAeQAAAECCAIAAACg0TMxAAAQvklEQVR4nO3d/09Vd57H8fvT/ZHsD6Y/OP2lP8x20+xOk30nPU2qBgmSMMHFbZdV4hDqdEXdjW2HTNTesTtKIpouk+KWkdGGWafI2BRLBeniIG6l0tEBpVpGCyMKYrwm9yTn8yfM/nDuvZz7DTiAfu7nnOcrjx9GOPdykeTp7edeMhHlKABAkYtofwQAgEURawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQ6/z6dkdS29OX/OCDvsa/K4lEomteO/iHB9ofIYBQCXCs+/ZECm9338I3zxProfeeS39sXdvtxR/A+HErt/h5v8Srx29q/+sCUNSIdX6+Ym3P3Rw61Vy7cW1jr/dOiDWAVUOs88t7DPKHg6+URCLRNZVHhz3HIP17o+lLiTWApyMcsbaOj/u8eb5YF9A7/3WINYCnhFjnR6wBFBVirZTz5Fb3wc3/sCYaiUQiJWs3Nn4xYeeJ9c3jr2adovQWOmhxb7K8WD+5deF4w8YX15a4nypZ+7cba5v7vvfeNj556WTDxhfcBxwpWSubD3b+6f78BeOt8490T6890dP42ppozr8lAEwS+lgnxjq2PJ8d2+jWrf+sJdYP+nbnPJjMm9sTZ3/6QjTPJT/Y0jFqu9d4Y7117970PRJrwFzhiHVu/JLZssd+9WrhqzJD+fRjbffuyZdhz80Tl9/7QeFHah3/1lEqM9YZ90KsAWOFO9aJvvk6Rl9+78KfHyWUik9eatrgiWbhWLtW78zaE9m/PzT8RDlKJR5N/6n/6L8c/tJRylF3T5anH+6GpkuTcaUSj27+z9bUewqfe28o634ikegLP/3k1hNHqfjk5H1ff4EAiki4Y+156/RLR695buup4vJjPdXxY3+x9t4gUvJKQ2v/6MyT/Hf40tFr8x+/nP421rfdVpmx/uEvh239PwsAKxWOWBc4s/bEL/mcNG1JLzC6Csbaeydbzz7M/up5zqwffrk3+5Qjuua1xu5v3WRf9vxaTv692jqusl9g1P6DALAKQh1rT9R+2HQ141OrEusv539dJvv+M593v/VFIvXx+8MnG15bk3V0Hd3w63G1yK/5EGsg0EIda7vnrfQl5Sfvzn8qMdL00irE2tvjl5pGMo4j7ngOWlIvDM6Lz44Ofdz4Skn6kucOXFbeQ/Dcm3gQayB4Qh1rNe7pb3RD0+DkE0fZczc7M94c5yPWz+/uuZfw3P/k77bM39HzW1ovTcaVcuxHN7r3vjz/ifS/E+O/aWhoPff1rdknjlKOsud6/+NvMr7i5QPpc5Doy3u7R+89sh2lHPvRvdH+1oaG34wn74dYA4ETjljnmZvgux0/zvtmuWg0mnVl4VgP5Z4kp19OtL1P0fPvpaaRVN8LveUuEolu+d2UcpS6U+DxRiKR1BmIItZAEIU81krd79uT887l6Ibjv3or58pCsXa+/fWGrIJ63vuRuNezN+8vsUQikUj0hb09f7HTd1Uo1s9v6RhLBf1Bb8G7I9ZAgIU+1o77ml7yl7eja360+eAXEwk/LzCm7mFtSb47d5Ry7HvfdDZvm/8V8kjJ2hc31jZ/8seMMxNHzY2dzbms4fiFW08yvzX7L3/sPLhZUr9uHilZ++I/bv7ZSfeMRSliDQRRgGMNAMFBrAHAAMQaAAxArAHAAMQaAAxArAHAAMQaAAxArAHAAMQaAAxArAHAAMQaAAxArAHAAGGL9Wz/oUpr3ZsdY4tc2RsTkdr20byfHWvfJiKxXv3fDoCwCGyse2OStdoTY8801qPttSIS6138g6vFvXMp2//5dMbHz8dS377+nwuA5Ql2rAvVdoU3L/JYi5Tt77nn+TixBsxHrJdx8+KOdXV1tUjZvp7p9MeJNWC+0MU66+P25FD7u6+XWiKyvrz+wJmReN7L4iNnDmwvtURkXXn9obZf1qRjPdt/qNKy6k7lnqssIdb2rZ5ju9yvLuvLf/77u+5l9tSl1INaV15/4Mw3j92P98ZEZNsHHUe3l1r5ip+8857BIxUZhyGZsZ4dPPlOfWXqi9Yf7rltey/7oCv5ta3S1989fX3yq/Z3/2m9iFil248OzP8D4MRvdh+uL3c/8/quD/unEjl/AwBWT7hjfa83tkkqGrtuPlbq8TdtdZZYjd0zOZd9d3qnJVZdy9CkrRJTQy11lmTF+o2PruY8hkVjnRhs3iRS3fTlpK0Sc6NnWjtHlXLU9PlYhVQ0nrkZd1R8JPmgZh2VjLVIRawnfxnTd+7ec/owJDPW410t7RdvzyVS37JUt47MXyZWXdtIXCWmzu0rExHLqvvg0pSdmOqJVYhYjZ/NKkcpx75+os6y6louTdmOPfV5rMK9F90/dCDAgh3rjNcX3fJ6KzzSWi2yo+O75E3snv0isvP091mXDbdUiVR98H+p/7PExEBT2Wocg4yf+omI/PsnmeVNPqiJ5B/tnn0isvP0XZWK9dufziz+Fe3B5gqRiljvtLPQMcjs2bfT37J7WdmRweRnzye/2qz7x8HmsvRnZ7obLSk7PJB8Su5cb6sRKWse1P1DBwIs2LFe+Jm1G8u8bxrJvWx/z3xSl3Zmfff0zkWOQSY++1lF8hjhaNfVSVs5qYLnPKj2UZU6BmkfK/QVM+7cHjxSIVIROz+dFWt78mrXh4feqd+8OXkWkvpUVtOz/ui98wvvW3keJO9lBJ6iMMfaba63wgtc5i3REt9n3RsTkZ+cGvd+8EpLVcaT3Pidr7qO7XIPhevar9nJJu7rsQvd4VJjnTpm2RTrPePJ7kz/+5tENu1p7bt2986DuLfIS4/1+ZiI1LRd1/5TBsIjzLFWg0fKRMqaBuyFb97/viVS1XIl9dmZ7kZrKbG+0b5N0ofgromOHXm/Yrz/P1OHDO5xQ9NAnn9CfMY6fRiyqaJQkSc6diwn1u5/NMyf1QB46kIdazV2qs4S2dTYdSOuHBX/88X2//r9eM5lbvKsuravH9rq8Z1zsQrPf/UXfjdI8qVCqWjsGn1oK8ee+7qtzhKr7tQN94LRzmMnLt55rJQTd1/c3NP5vXLUjVN1lqRe9nTidy62t3SNK0ctI9apwxDPWYf7b8G+c1MJFb/R1bhpWccgzmz/+xUiVl3L0FRCqcTcaPfhE/+r/4cOBFi4Y+2+J899A5rI+vKaXf89OJvnMvt2z+Ht6ff3ne1p2yaLvxvEUck34dV47v9oz+30U+a7n/9i/lP1Bzq+Sr0xLv5NZ8aD+mjQfQ/GMmKdOgyZz+70V627y9dJ8m17H+9fVqyVSkz1f5h616FVWll/4LPFfikUwEoENtYAECTEGgAMQKwBwADEGgAMQKwBwADEGgAMQKwBwADEGgAMQKwBwADBjPUcY6zopz0UZglsrP/KGCviEWu/iDVjTMOItV/EmjGmYcTaL2LNGNMwYu0XsWaMaRix9otYM8Y0jFj7RawZYxpGrP0i1owxDSPWfhFrxpiGEWu/iDVjTMOItV/EmjGmYcTaL2LNGNMwYu0XsWaMaRix9otYM8Y0jFj7RawZYxpGrP0i1owxDSPWfhFrxpiGEWu/iDVjTMOItV/EmjGmYcTaL2LNGNMwYu0XsWaMaRix9otYM8Y0jFj7RawZYxpGrP0i1owxDSPWfhFrxpiGEWu/iDVjTMOItV/EmjGmYcTaL2LNGNMwYu0XsWaMaRix9iuwsWaMFfm0h8IswYw1AAQMsQYAAxBrADAAsQYAAxBrADAAsQYAAxBrADAAsQYAAxBrADAAsQYAAxBrADBAOGM923+o0lr3ZseY9kcCAEsS7FjbU1e7ju2qKV8nIiKyvrzmF5/fVcQagHECHOvpgSNvWLJ+66Fz1+7HlaPsh7cvnjjWOZp75UjnO/WV/3ZqTP9jBoD8AhvridM7LbHqTly3F7+4NyYi29qJNYCiFdRYDzaXiVS3jhS4oDcmIrXto0qdj4l329qHP2u0RKpahtMXj7RWi5Q1Ddi6vykA4RXQWF9rqxEpOzJY6IL5WDsq+5n1THey1smLR1qrF+o+ADwDAY31+ZiI1J4YK3TBQrF27IHDZSJVLVeUcpS60lIlsqNjQv83BSDEAhrrweayzKOMLAvGWrkHH+7Nh91Wf6f7OwIQbgGN9cynb4vIjo6JAhcsEmtnomOHexIy3FIlVmP3rPbvCEC4BTTWjj14pEKkInZ+Ou8Fi8VafX96p0h166nmMl5aBFAEghprpRLX2+sssSr3/fbK7Ye2clT8/rULrcn3WWfGerilSsR6+9N7npvPdDdaYlmWlDUNJHR/LwBCL7ixdpRKTA11HKivLLVERMQqrazZ9dHgjFLZsVbTA8e2l1oiYr3ZMZ68ufsyo1S3juj/RgCEXqBjvTKDR8p4aRFAkSDWhQy3VIm183ShlygB4Fki1nnFb37cYElt2zVeWgRQFIh1jtH2WhGrdPuxgfzvJAGAZ49YA4ABiDUAGIBYA4ABiDUAGIBYA4ABghnrOcZY0U97KMwS2Fj/lTFWxCPWfhFrxpiGEWu/iDVjTMOItV/EmjGmYcTaL2LNGNMwYu0XsWaMaRix9otYM8Y0jFj7RawZYxpGrP0i1owxDSPWfhFrxpiGEWu/iDVjTMOItV/EmjGmYcTaL2LNGNMwYu0XsWaMaRix9otYM8Y0jFj7RawZYxpGrP0i1owxDSPWfhFrxpiGEWu/iDVjTMOItV/EmjGmYcTaL2LNGNMwYu0XsWaMaRix9otYM8Y0jFj7RawZYxpGrP0i1owxDSPWfhFrxpiGEWu/iDVjTMOItV/EmjGmYcTaL2LNGNMwYu1XYGPNGCvyaQ+FWYIZawAIGGINAAYg1gBgAGINAAYg1gBgAGINAAYg1gBgAGINAAYg1gBgAGINAAYg1gBggGDG+kDxTfvfCQCjBTbWE9OzxYNYA1ghYk2sARiAWBNrAAYg1sQagAGINbEGYABiTawBGIBYE2sABghprEVERJZX3mXcllgDWCFinfzfuVvFXhNrACtErPOUl1gDKDbEepFYF3re7ev5OLEGsELhinVuW3/bdXYZxyB+EWsAKxSuWHur/UbNv/o6BilU8KWUnVgDWCFivdJYL6XXxBrACoU61ks/Bln0afXCvSbWAFYovLFe+sH0AkUm1gCejTDG2lvqQk+rl3JCvfTcE2sAKxSuWLt5TR99+D16Tl9W6B6INYCnJFyxXvgJ8jIORog1gGeDWGfHetHjbJ5ZA3j2iLWPZ9ZZHefMGsAzE7pYZz0vTv9x4SfLhZ5uL/o0nFgDWBWhi3Whp9KSb0vM8aKHJ8QawAqFMdbPHrEGsELEmlgDMACxJtYADECsiTUAAxBrYg3AAMSaWAMwALEm1gAMQKyJNQADEGtiDcAAxJpYAzBAYGNdbNP+dwLAaMGMNQAEDLEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwALEGAAMQawAwwP8Djd7qitJo2BwAAAAASUVORK5CYII=" alt="" />

  导航属性的自定义资源信息也会被显示。这里就可以看出p => p.Address.City时,Provider中的ContainerType则为Address的实际类型,ModelMetadata中的Model则为实际上要显示的子类型的属性。

  问题:

  我们通过对ModelMetadata内部的属性进行修改,从而实现自定义资源的使用。这种方式属于高阶应用,有必要深入了解MVC的模型绑定相关的知识。本人在完成这篇文章的时候,耗费了相当长的时间(粗略统计大概有3天时间)。主要是想解决多个同类型属性该如何显示不同的自定义资源。例如在UserProfile类型中定义两个同为Address类型的属性,分别为UserAddress、和CompanyAddress。若同时在页面显示这两个属性的City名称,则显示的内容是相同的,都指向同一个资源:

<resource key="Address.City" value="City"/>。但始终未能在第二种方案下找到适合的解决办法。希望有达人能为在下解惑,不胜感激!!!

  下期预告:第三中方案解决同类型导航属性显示不同的自定义资源。