ASP.NET MVC - 接口类型上的自定义模型绑定器

问题描述 投票:0回答:3

我不确定这种行为是否符合预期,但当绑定分配给接口类型时,自定义模型绑定似乎不起作用。有人尝试过这个吗?

public interface ISomeModel {}
public class SomeModel : ISomeModel {}

public class MvcApplication : HttpApplication {
    protected void Application_Start(object sender, EventArgs e) {
        ModelBinders.Binders[typeof(ISomeModel)] = new MyCustomModelBinder();
    }
}

使用上面的代码,当我绑定到 SomeModel 类型的模型时,MyCustomModelBinder 永远不会被命中;但是,如果我更改上面的代码并用

typeof(ISomeModel)
替换
typeof(SomeModel)
并发布完全相同的表单,MyCustomModelBinder 将按预期被调用。看起来是这样吗?


编辑

在我最初提出这个问题一年多后,我发现自己又回到了这个困境,现在我有了一个有效的解决方案。谢谢马特·希丁格!

https://web.archive.org/web/20191202065649/http://matthidinger.com:80/archive/2011/08/16/An-inheritance-aware-ModelBinderProvider-in-MVC-3/

asp.net-mvc interface modelbinders
3个回答
11
投票

我正在尝试解决这个问题,并想出了一个解决方案。我创建了一个名为 InterfaceModelBinder 的类:

public class InterfaceModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        ModelBindingContext context = new ModelBindingContext(bindingContext);
        var item = Activator.CreateInstance(
            Type.GetType(controllerContext.RequestContext.HttpContext.Request.Form["AssemblyQualifiedName"]));

        Func<object> modelAccessor = () => item;
        context.ModelMetadata = new ModelMetadata(new DataAnnotationsModelMetadataProvider(),
            bindingContext.ModelMetadata.ContainerType, modelAccessor, item.GetType(), bindingContext.ModelName);

        return base.BindModel(controllerContext, context);
    }
}

我在 Application_Start 中注册如下:

ModelBinders.Binders.Add(typeof(IFormSubmission), new InterfaceModelBinder.Models.InterfaceModelBinder());

接口和具体实现如下所示:

public interface IFormSubmission
{
}

public class ContactForm : IFormSubmission
{
    public string Name
    {
        get;
        set;
    }

    public string Email
    {
        get;
        set;
    }

    public string Comments
    {
        get;
        set;
    }
}

整个方法的唯一缺点(正如您可能已经收集到的那样)是我需要从某个地方获取 AssemblyQualifiedName,在本示例中,它被存储为客户端的隐藏字段,如下所示:

<%=Html.HiddenFor(m => m.GetType().AssemblyQualifiedName) %>

尽管我不确定向客户端公开类型名称的缺点是否值得失去这种方法的好处。像这样的操作可以处理我所有的表单提交:

[HttpPost]
public ActionResult Process(IFormSubmission form)
{
    if (ModelState.IsValid)
    {
        FormManager manager = new FormManager();
        manager.Process(form);
    }

    //do whatever you want
}

对这种方法有什么想法吗?



5
投票

我不确定它是否直接相关,但是是的,在使用模型绑定和接口时,您需要考虑一些事情...我在默认模型绑定程序中遇到了类似的问题,但它可能不直接相关,具体取决于你做事的方式...

看看以下内容: ASP.net MVC v2 - 调试模型绑定问题 - BUG? ASP.net MVC v2 - 调试模型绑定问题 - BUG?

© www.soinside.com 2019 - 2024. All rights reserved.