多态模型绑定 [英] Polymorphic model binding

查看:103
本文介绍了多态模型绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题已经在早期版本之前问MVC的。还有约一个方法来解决此问题这篇博客。如果MVC3已经推出任何可能有助于我在想,如果有任何其他选项。

This question has been asked before in earlier versions of MVC. There is also this blog entry about a way to work around the problem. I'm wondering if MVC3 has introduced anything that might help, or if there are any other options.

在一言以蔽之。这里的情况。我有一个抽象的示范基地和2个具体子类。我有一个强类型的观点,即呈现型号 EditorForModel()。然后,我有自定义模板呈现每个具体类型。

In a nutshell. Here's the situation. I have an abstract base model, and 2 concrete subclasses. I have a strongly typed view that renders the models with EditorForModel(). Then I have custom templates to render each concrete type.

问题出现在后的时间。如果我做出后的操作方法把基类作为参数,然后MVC不能创建它的一个抽象的版本(我不希望不管怎么说,我会希望它来创建实际的具体类型)。如果我创建多个岗位的操作方法,只有通过参数签名不同,那么MVC抱怨说,它是不明确的。

The problem comes at post time. If I make the post action method take the base class as the parameter, then MVC can't create an abstract version of it (which i would not want anyways, i'd want it to create the actual concrete type). If I create multiple post action methods that vary only by parameter signature, then MVC complains that it's ambiguous.

所以,据我所知,我对如何解决这个proble几个选择。我不喜欢任何人因各种原因,但我会在这里一一列举:

So as far as I can tell, I have a few choices on how to solve this proble. I don't like any of them for various reasons, but i will list them here:


  1. 创建一个自定义的模型绑定为达林建议在第一篇文章我联系。

  2. 创建一个鉴别属性作为第二个职位我挂暗示。

  3. 发布到基于类型不同的操作方法

  4. ???

我不喜欢1,因为它基本上是配置的是隐藏的。其他一些开发商在code工作可能不知道这件事,浪费了很多时间试图弄清楚为什么事情打破时,改变的东西。

I don't like 1, because it is basically configuration that is hidden. Some other developer working on the code may not know about it and waste a lot of time trying to figure out why things break when changes things.

我不喜欢2,因为它似乎有点哈克。不过,我倾向于这种方式。

I don't like 2, because it seems kind of hacky. But, i'm leaning towards this approach.

我不喜欢3,因为这意味着违反干。

I don't like 3, because that means violating DRY.

任何其他建议?

编辑:

我决定去与达林的方法,但做了细微的变化。我说这我的抽象模型:

I decided to go with Darin's method, but made a slight change. I added this to my abstract model:

[HiddenInput(DisplayValue = false)]
public string ConcreteModelType { get { return this.GetType().ToString(); }}

然后,自动隐藏在获取生成我的 DisplayForModel()。你要记住的唯一的事情是,如果你不使用 DisplayForModel(),你必须将它自己添加。

Then a hidden automatically gets generated in my DisplayForModel(). The only thing you have to remember is that if you're not using DisplayForModel(), you'll have to add it yourself.

推荐答案

由于我明明选择选项1(:-))让我尝试阐述多一点,使其较少的易碎避免硬编码的具体事例到模型粘合剂。我们的想法是具体类型传递到一个隐藏字段,并使用反射来实例化具体类型。

Since I obviously opt for option 1 (:-)) let me try to elaborate it a little more so that it is less breakable and avoid hardcoding concrete instances into the model binder. The idea is to pass the concrete type into a hidden field and use reflection to instantiate the concrete type.

假设你有以下视图模型:

Suppose that you have the following view models:

public abstract class BaseViewModel
{
    public int Id { get; set; }
}

public class FooViewModel : BaseViewModel
{
    public string Foo { get; set; }
}

以下控制器:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new FooViewModel { Id = 1, Foo = "foo" };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(BaseViewModel model)
    {
        return View(model);
    }
}

相应的首页查看:

@model BaseViewModel
@using (Html.BeginForm())
{
    @Html.Hidden("ModelType", Model.GetType())    
    @Html.EditorForModel()
    <input type="submit" value="OK" />
}

〜/查看/主页/ EditorTemplates / FooViewModel.cshtml 编辑模板:

@model FooViewModel
@Html.EditorFor(x => x.Id)
@Html.EditorFor(x => x.Foo)

现在,我们可以有以下的自定义模型粘合剂:

Now we could have the following custom model binder:

public class BaseViewModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        var typeValue = bindingContext.ValueProvider.GetValue("ModelType");
        var type = Type.GetType(
            (string)typeValue.ConvertTo(typeof(string)),
            true
        );
        if (!typeof(BaseViewModel).IsAssignableFrom(type))
        {
            throw new InvalidOperationException("Bad Type");
        }
        var model = Activator.CreateInstance(type);
        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, type);
        return model;
    }
}

实际的类型由 ModelType 隐藏字段的值推断。不难codeD,这意味着你可以添加其他类型的孩子后,无需触碰过这个模型粘合剂。

The actual type is inferred from the value of the ModelType hidden field. It is not hardcoded, meaning that you could add other child types later without having to ever touch this model binder.

这同样的技术可能是<一个href=\"http://stackoverflow.com/questions/6484972/viewmodel-with-listbaseclass-and-editor-templates/6485552#6485552\">easily适用以基本视图模型的集合。

This same technique could be easily be applied to collections of base view models.

这篇关于多态模型绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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