首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在MVC DataAnnotations和MetaDataType中使用多个接口

在MVC DataAnnotations和MetaDataType中使用多个接口
EN

Stack Overflow用户
提问于 2011-10-19 13:13:17
回答 3查看 1.7K关注 0票数 5

我正在使用DataAnnotations对一个MVC ViewModel进行验证,它是由几个实体框架对象和一些自定义逻辑组成的。已经为接口中的entity对象定义了验证,但是如何将此验证应用于ViewModel?

我最初的想法是将这些接口组合成一个接口,并将组合后的接口应用于ViewModel,但这并不起作用。下面是一些示例代码,演示了我的意思:

代码语言:javascript
运行
复制
// interfaces containing DataAnnotations implemented by entity framework classes
public interface IPerson
{
    [Required]
    [Display(Name = "First Name")]
    string FirstName { get; set; }

    [Required]
    [Display(Name = "Last Name")]
    string LastName { get; set; }

    [Required]
    int Age { get; set; }
}
public interface IAddress
{
    [Required]
    [Display(Name = "Street")]
    string Street1 { get; set; }

    [Display(Name = "")]
    string Street2 { get; set; }

    [Required]
    string City { get; set; }

    [Required]
    string State { get; set; }

    [Required]
    string Country { get; set; }
}

// partial entity framework classes to specify interfaces
public partial class Person : IPerson {}
public partial class Address : IAddress {}

// combined interface
public interface IPersonViewModel : IPerson, IAddress {}

// ViewModel flattening a Person with Address for use in View
[MetadataType(typeof(IPersonViewModel))] // <--- This does not work. 
public class PersonViewModel : IPersonViewModel
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public int Age { get; set; }

    public string Street1 { get; set; }

    public string Street2 { get; set; }

    public string City { get; set; }

    public string State { get; set; }

    public string Country { get; set; }
}

我的实际问题涉及到ViewModel上的大约150个属性,所以它不像示例那么微不足道,重新输入所有属性似乎是对DRY的可怕违反。

对于如何实现这一点有什么想法吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-06-13 05:52:26

为了使其正常工作,您需要手动将接口作为具体类的元数据进行关联。

我希望能够添加多个MetadataType属性,但这是不允许的。

代码语言:javascript
运行
复制
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] // Notice AllowMultiple
public sealed class MetadataTypeAttribute : Attribute

因此,这会产生一个编译错误:

代码语言:javascript
运行
复制
[MetadataType(typeof(IPerson))] 
[MetadataType(typeof(IAddress))] // <--- Duplicate 'MetadataType' attribute 
public class PersonViewModel : IPersonViewModel

但是,如果您只有一个接口,则它可以工作。因此,我的解决方案是简单地使用AssociatedMetadataTypeTypeDescriptionProvider关联接口,并将其包装在另一个属性中。

代码语言:javascript
运行
复制
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class MetadataTypeBuddyAttribute : Attribute
{
    public MetadataTypeBuddyAttribute(Type modelType, Type buddyType)
    {
        TypeDescriptor.AddProviderTransparent(
           new AssociatedMetadataTypeTypeDescriptionProvider(
               modelType,
               buddyType
           ),
           modelType);
    }
}

在我的情况下(MVC4),我的接口上的数据注释属性已经起作用了。这是因为我的模型直接实现接口,而不是多级继承。但是,在接口级别实现的自定义验证属性不起作用。

只有在手动关联接口时,所有自定义验证才会相应地工作。如果我对你的情况理解正确的话,这也是你问题的解决方案。

代码语言:javascript
运行
复制
[MetadataTypeBuddy(typeof(PersonViewModel), typeof(IPerson))] 
[MetadataTypeBuddy(typeof(PersonViewModel), typeof(IAddress))]
public class PersonViewModel : IPersonViewModel
票数 8
EN

Stack Overflow用户

发布于 2017-01-12 15:48:03

根据这里的答案,我不能以某种方式使MetadataTypeBuddy属性工作。我确信我们必须在某个地方设置MVC应该调用该属性。当我在Application_Start()中手动运行该属性时,我设法让它正常工作,如下所示

代码语言:javascript
运行
复制
new MetadataTypeBuddyAttribute(typeof(PersonViewModel), typeof(IPerson));
new MetadataTypeBuddyAttribute(typeof(PersonViewModel), typeof(IAddress));
票数 1
EN

Stack Overflow用户

发布于 2020-05-10 10:43:59

MetadataTypeBuddy属性对我不起作用。

但是在"Startup“中添加" new”MetadataTypeBuddyAttribute确实有效,但它可能会导致开发人员不知道在任何新类的"Startup“中添加它的复杂代码。

注意:您只需要在每个类的应用程序启动时调用AddProviderTransparent一次。

下面是为一个类添加多个元数据类型的线程安全方法。

代码语言:javascript
运行
复制
    [AttributeUsage(AttributeTargets.Class)]
    public class MetadataTypeMultiAttribute : Attribute
    {
        private static bool _added = false;
        private static readonly object padlock = new object();

        public MetadataTypeMultiAttribute(Type modelType, params Type[] metaDataTypes)
        {
            lock (padlock)
            {
                if (_added == false)
                {
                    foreach (Type metaDataType in metaDataTypes)
                    {
                        System.ComponentModel.TypeDescriptor.AddProviderTransparent(
                            new AssociatedMetadataTypeTypeDescriptionProvider(
                                modelType,
                                metaDataType
                            ),
                            modelType);
                    }

                    _added = true;
                }
            }
        }
    }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7816819

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档