Rob*_*rkk 5 c# reflection asp.net-mvc data-annotations
我的问题类似于此问题,但不是通过反射将Data Annotations应用于属性Name(由ModelMetadata.DisplayName处理),而是将其应用于值(未由ModelMetadata处理)。
在ASP.NET MVC程序的上下文中。
假设我有一个Model类
public class Model
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string NickName { get; set; }
public string Address { get; set; }
public int Phone { get; set; }
[Display(Name = "Start Date")]
[DataType(DataType.Date)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime StartDate { get; set }
[Display(Name = "End Date")]
[DataType(DataType.Date)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime EndDate { get; set }
}
Run Code Online (Sandbox Code Playgroud)
然后,假设该模型至少在5个不同的视图中使用,其中每个属性的值都必须完整显示。(有时是每种情况,有时是几次,一次是)。
我可以手动列出每个
<td>@Html.DisplayFor(item.<Property>)</td>
视图中每个属性的访问权限。
但这对以后的Model定义扩展为包括新的Properties(例如Description,Relation and Reliability)不会帮助我。然后,我需要手动更新每次出现的完整Model清单。
我可以使用反射来遍历PropertyInfo的列表,并节省使用以下方法手动列出每个属性的麻烦
<td>@property.GetValue(item)</td>
但DisplayFor(x)不支持表达复杂的x=>property.GetValue(item),而这意味着我失去了数据注释该格式我的日期时间作为
01/01/1990
代替
01-Jan-90 12:00:00 AM
,并可能也会导致所有类型的注释,包括确认的损失。
到目前为止,我已经考虑(并在某些情况下尝试过)以下解决方案:
@property.GetValue(item)DisplayFor(x => property.GetGetMethod()),并.Invoke在x上对其进行显示。最后一个解决方案将把解决方案
@Html.DisplayFor(m=>property.GetValue(item)
转变为理论上
@Html.DisplayFor(m=>item.Properties[i].Value)
可行的方案,除了通过(.Value)获取名称为Name(Properties [“ Name”])的属性的需求有点不直观之外,这似乎是最可行的解决方案,但以模型清晰为代价。
[编辑]
最近,我创建了一个Utility方法,该方法从PropertyInfo中检索DisplayFormatAttribute,如果未注释格式字符串,则返回DisplayFormatString或默认值“ {0}”。然后,我用它在ViewModel中创建了一组预格式化的属性值。就目前而言,这似乎是我所知道的最优雅的方法,即在仍从视图中检索必要数据的同时,尽可能地将视图与模型分离。
[/编辑]
目前,这纯粹是一种学习练习,但我想知道...
在失败的地方取得成功,并且都拥有自己的Reflection蛋糕并且也可以吃数据注释,这是否有可能成功?还是我必须寻求替代解决方案?
如果我必须寻求替代解决方案,是我错过了某些路线,还是至少在正确的轨道上?
重新审视我最初动态手动创建表达式的尝试,我发现这篇文章正是我想做的,并且主要使用了 Microsoft 提供的代码!
尽管很难找到 Microsoft 代码(文章中的链接已损坏,并且示例对于我找到的代码来说稍微过时),但我能够使用它来实现我自己的 DisplayFor 扩展方法,效果良好。
不幸的是,由于我的模型是一个列表而不是单个实例,我仍然需要创建一个部分视图来传递实例,以便我可以从生成的表达式中通过模型访问属性。
我的视图代码现在如下所示:
@foreach (var thing in Model.CollectionOfThings)
{
<tr>
@foreach (var prop in typeof(Thing).GetProperties())
{
<td>
@{
Html.RenderPartial("~/Views/Shared/_DisplayForReflectedProperty.cshtml",
new Tuple<Thing, PropertyInfo>(thing, prop));
}
</td>
}
}
Run Code Online (Sandbox Code Playgroud)
使用 _DisplayForReflectedProperty 就这么简单
@using WebApplication1.Models
@using System.Reflection
@using WebApplication1.Extensions
@model Tuple<Thing, PropertyInfo>
@Html.DisplayFor("Item1."+Model.Item2.Name)
Run Code Online (Sandbox Code Playgroud)
我的 DisplayFor 扩展与本文中的扩展之间的唯一区别是此函数调用中的空对象参数(加上从 EditorFor 到 DisplayFor 的明显转换):
var lambda = System.Linq.Dynamic.DynamicExpression.ParseLambda(typeof(TModel),
null, expression);
Run Code Online (Sandbox Code Playgroud)
使用此模板,我现在可以生成模型属性的任意(从代码角度来看,从业务规则角度来看特定)子集,以我希望的任何方式显示,而无需针对每个特定子集定制视图,同时保留使用“For”助手!