我可以在动作过滤器中修改模型元数据吗?

时间:2012-06-07 17:12:20

标签: asp.net-mvc-3

我正在尝试实现一个允许我根据用户角色或其他业务逻辑更改html控件状态的要求。例如,某些用户不应该能够编辑某个模型属性,或者在某些情况下我甚至不希望控件呈现给html DOM。

在HTML帮助程序中,元数据可以告诉帮助程序是否呈现控件,或者它可以使其成为只读/禁用。而不是在这里重新发明轮子,我只想通过在运行时基于逻辑更改动作过滤器中的元数据来使用已经存在的内容。我不希望在我的视图中使用这个逻辑,如果我不需要,我不想为每个单独的html控件创建自定义助手。

我尝试做的是创建一个动作过滤器来处理我的业务层中的逻辑规则评估,然后更改给定model.property的元数据。

问题是我对元数据的修改似乎没有进入视图。我似乎对动作过滤器中的元数据的更改不是通过引用,因此我不修改用于视图的相同实例?

public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
    var trans = filterContext.Controller.ViewData.ModelMetadata.Properties.Where(e => e.PropertyName == "Transaction").FirstOrDefault();
    trans.DisplayName = "Show FOO!";
}

我做错了什么?

2 个答案:

答案 0 :(得分:1)

您无法更改过滤器中的ModelMetadata.Properties值,实际上根本无法更改它们。

问题出在内置的DataAnnotationsModelMetadataProvider(准确地说是AssociatedMetadataProvider的{​​{1}}方法)中,每次迭代时都会从属性中重新生成GetMetadataForProperties它。

因此ModelMetadata.Properties集合中的项目是不可变的。

您可以通过调试来检查它:

ModelMetadata.Properties

public override void OnResultExecuting(ResultExecutingContext filterContext) { var properties = filterContext.Controller.ViewData.ModelMetadata.Properties var trans1 = properties.Where(e => e.PropertyName == "Transaction").First(); trans1.DisplayName = "Show FOO!"; var trans2 = properties.Where(e => e.PropertyName == "Transaction").First(); } trans1将是不同的实例(您可以检查其哈希码),因此trans2 displayname将是原始显示名称而非“显示FOO!”。

所以你需要扩展/写一个新的trans2来实现你的目标。

答案 1 :(得分:0)

您可以在视图中检查用户的角色并以此方式进行调整。在呈现html

之前,角色在服务器端进行评估
@if(HttpContext.Current.User.IsInRole("MyRole")) {
   <input type='text' id='txtSomeInput' />
}