如何与QUOT;干涸" C#中的模式和属性的ViewModels? [英] How to "DRY up" C# attributes in Models and ViewModels?

查看:82
本文介绍了如何与QUOT;干涸" C#中的模式和属性的ViewModels?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这问题是由我的挣扎与ASP.NET MVC的启发,但我认为它也适用于其他的情况也是如此。

This question was inspired by my struggles with ASP.NET MVC, but I think it applies to other situations as well.

让我们说我有一个ORM生成的模型和两个的ViewModels(一个用于详细信息视图,一个用于编辑视图):

Let's say I have an ORM-generated Model and two ViewModels (one for a "details" view and one for an "edit" view):

型号

public class FooModel // ORM generated
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string EmailAddress { get; set; }
    public int Age { get; set; }
    public int CategoryId { get; set; }
}

显示视图模型

public class FooDisplayViewModel // use for "details" view
{
    [DisplayName("ID Number")]
    public int Id { get; set; }

    [DisplayName("First Name")]
    public string FirstName { get; set; }

    [DisplayName("Last Name")]
    public string LastName { get; set; }

    [DisplayName("Email Address")]
    [DataType("EmailAddress")]
    public string EmailAddress { get; set; }

    public int Age { get; set; }

    [DisplayName("Category")]
    public string CategoryName { get; set; }
}

修改视图模型

public class FooEditViewModel // use for "edit" view
{
    [DisplayName("First Name")] // not DRY
    public string FirstName { get; set; }

    [DisplayName("Last Name")] // not DRY
    public string LastName { get; set; }

    [DisplayName("Email Address")] // not DRY
    [DataType("EmailAddress")] // not DRY
    public string EmailAddress { get; set; }

    public int Age { get; set; }

    [DisplayName("Category")] // not DRY
    public SelectList Categories { get; set; }
}

请注意,在对的ViewModels属性是不会干 - 很多信息是重复的。现在想象一下这个场景乘以10或100,你可以看到,它可以很快变得相当繁琐且容易出错,以确保整个的ViewModels的一致性(以及由此引起的意见)。

Note that the attributes on the ViewModels are not DRY--a lot of information is repeated. Now imagine this scenario multiplied by 10 or 100, and you can see that it can quickly become quite tedious and error prone to ensure consistency across ViewModels (and therefore across Views).

如何干起来这code?

在你回答之前,只要把所有的属性上 FooModel ,我已经试过了,但它并没有工作,因为我需要保持我的ViewModels平面。换句话说,我不能只组成每个视图模型与模型 - 我需要我的视图模型只具有的属性(和属性)应由查看被消耗掉,并在视图不能钻入子属性得到的值。

Before you answer, "Just put all the attributes on FooModel," I've tried that, but it didn't work because I need to keep my ViewModels "flat". In other words, I can't just compose each ViewModel with a Model--I need my ViewModel to have only the properties (and attributes) that should be consumed by the View, and the View can't burrow into sub-properties to get at the values.

更新

LukLed的答案建议使用继承。这绝对降低了非干code量,但它不能消除它。需要注意的是,在我上面的例子中,为类别显示名称属性属性需要,因为数据被写入两次属性的类型是显示和编辑的ViewModels之间不同。这不会是一个小规模的一个大问题,但作为一个项目的大小和复杂程度最高可扩展至(想象一个更多的属性,每个属性的详细属性,每个模型更多的意见),还有潜在的重复自己相当数量。也许我正在干太远这里,但我还是宁愿我所有的好记的名称,数据类型,验证规则等输入了一次。

LukLed's answer suggests using inheritance. This definitely reduces the amount of non-DRY code, but it doesn't eliminate it. Note that, in my example above, the DisplayName attribute for the Category property would need to be written twice because the data type of the property is different between the display and edit ViewModels. This isn't going to be a big deal on a small scale, but as the size and complexity of a project scales up (imagine a lot more properties, more attributes per property, more views per model), there is still the potentially for "repeating yourself" a fair amount. Perhaps I'm taking DRY too far here, but I'd still rather have all my "friendly names", data types, validation rules, etc. typed out only once.

推荐答案

我假设你这样做是为了利用HtmlHelpers EditorFor和DisplayFor的,不希望在整个4000次隆重宣布同样的事情的开销应用程序。

I'll assume that your doing this to take advantage of the HtmlHelpers EditorFor and DisplayFor and don't want the overhead of ceremoniously declaring the same thing 4000 times throughout the application.

干这件事的最简单方法是实现自己的ModelMetadataProvider。该ModelMetadataProvider是什么是读那些属性和$ P $他们psenting到模板帮手。 MVC2已经提供了DataAnnotationsModelMetadataProvider实现把事情会这么沿用,使得事情很容易。

The easiest way to DRY this up is to implement your own ModelMetadataProvider. The ModelMetadataProvider is what is reading those attributes and presenting them to the template helpers. MVC2 already provides a DataAnnotationsModelMetadataProvider implementation to get things going so inheriting from that makes things really easy.

要得到你开始在这里的是,除了打破驼峰属性名称为空格一个简单的例子,名字=>名字:

To get you started here is a simple example that breaks apart camelcased property names into spaces, FirstName => First Name :

public class ConventionModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {
        var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);

        HumanizePropertyNamesAsDisplayName(metadata);

        if (metadata.DisplayName.ToUpper() == "ID")
            metadata.DisplayName = "Id Number";

        return metadata;
    }

    private void HumanizePropertyNamesAsDisplayName(ModelMetadata metadata)
    {
        metadata.DisplayName = HumanizeCamel((metadata.DisplayName ?? metadata.PropertyName));
    }

    public static string HumanizeCamel(string camelCasedString)
    {
        if (camelCasedString == null)
            return "";

        StringBuilder sb = new StringBuilder();

        char last = char.MinValue;
        foreach (char c in camelCasedString)
        {
            if (char.IsLower(last) && char.IsUpper(c))
            {
                sb.Append(' ');
            }
            sb.Append(c);
            last = c;
        }
        return sb.ToString();
    }
}

然后,所有你需要做的就是像添加自定义的视图引擎或的ControllerFactory Global.asax中的应用程序启动的内部注册它:

Then all you have to do is register it like adding your own custom ViewEngine or ControllerFactory inside of Global.asax's Application Start:

ModelMetadataProviders.Current = new ConventionModelMetadataProvider();

现在只是向你展示我使用来获得相同的的HtmlHelper我不会骗这是视图模型*对于以经验为装饰视图模型:

Now just to show you I'm not cheating this is the view model I'm using to get the same HtmlHelper.*.For experience as your decorated ViewModel:

    public class FooDisplayViewModel // use for "details" view
    {
        public int Id { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        [DataType("EmailAddress")]
        public string EmailAddress { get; set; }

        public int Age { get; set; }

        [DisplayName("Category")]
        public string CategoryName { get; set; }
    }

这篇关于如何与QUOT;干涸&QUOT; C#中的模式和属性的ViewModels?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆