从ASP.NET MVC的ModelMetadataProvider获取包含对象实例

14

在ASP.NET MVC2中实现自定义DataAnnotationsModelMetadataProvider

假设要呈现的对象如下所示:

- Contact : IUpdateable
   - Name: string
   - ContactType: (Lead, Prospect, Customer)

下面的方法是在上下文中使用 Contact.ContactType,这意味着:

  • meta.PropertyName == "ContactType"
  • meta.ContainerType == typeof(Contact)
  • meta.Model == ContactType.Lead

(疑问所涉及的代码:)

protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, 
    Type containerType,
    Func<object> modelAccessor, 
    Type modelType, string propertyName) {

    var containerInstance = meta.NotSureWhatGoesHere as IUpdateable;
    meta.IsReadOnly = containerInstance != null && containerInstance.CanBeUpdated(meta.PropertyName);
}

问题: 如何从元数据中获取 Contact 的 实例?(将 NotSureWhatGoesHere 替换为正确的参数)

谢谢。

3个回答

11

不太规范的方法(在mvc3中测试过):

object target = modelAccessor.Target;
object container = target.GetType().GetField("container").GetValue(target);

它将返回模型中的model => model.Contact.Name而不是model.Contact。其余部分留给读者自行练习;)。就像所有反射基础解决方案一样,这种方法在探索非公共数据时不提供保证。


这是一个有趣的技巧!稍后会尝试一下。谢谢。 - Dmytrii Nagirniak
1
这似乎比那更为复杂。需要遍历一个表达式树(并编译其中的一部分),并根据元信息神奇地找到容器。元数据没有提供任何关于容器实例的详细信息,可以识别所需的容器实例(容器名称和类型不足以做到这一点,因为它们可能有很多个)。 - Dmytrii Nagirniak
对于其他人来说,这个解决方案要么在MVC2中不起作用,要么比这更复杂。我们最终选择了另一种方法,并没有修改元数据提供程序以获取实例值的访问权限。 - TLS

2
我认为你做不到。我直接问了Brad Wilson(ModelMetadata等的作者),他也想不出一种方法。最终,我不得不走另外一条路。

非常感谢。听起来很令人失望。您知道在这方面从MVC2到MVC3是否有任何变化吗? - Dmytrii Nagirniak
@Dmytrii,我还没有在MVC 3中查看过这个。 - Craig Stuntz
在MVC3或MVC4中似乎没有改变。CreateMetadata方法仍然只传递容器类型,而不是实例。 - Ben Foster

0

这不是 modelAccessor 参数的作用吗?

尝试:

var containerInstance = modelAccessor() as IUpdateable;

不,他在ContactType.Lead的上下文中。在这种情况下,modelAccessor()返回与meta.Model相同的内容;唯一的区别是,如果modelAccessor为空,您的代码将失败,但meta.Model会返回null。 - Craig Stuntz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接