c# - 继承自 DefaultModelBinder 的自定义模型绑定(bind)器

标签 c# asp.net-mvc-4 model-binding

我正在尝试为 MVC 4 构建自定义模型绑定(bind)器,它将继承自 DefaultModelBinder。我希望它在任何 绑定(bind)级别拦截任何接口(interface),并尝试从名为 AssemblyQualifiedName 的隐藏字段中加载所需的类型。

这是我目前所拥有的(已简化):

public class MyWebApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ModelBinders.Binders.DefaultBinder = new InterfaceModelBinder();
    }
}

public class InterfaceModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, 
        ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType.IsInterface 
            && controllerContext.RequestContext.HttpContext.Request.Form.AllKeys.Contains("AssemblyQualifiedName"))
        {
            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);
        }

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

示例 Create.cshtml 文件(已简化):

@model Models.ScheduledJob

@* Begin Form *@
@Html.Hidden("AssemblyQualifiedName", Model.Job.GetType().AssemblyQualifiedName)

@Html.Partial("_JobParameters")
@* End Form *@

上面的部分 _JobParameters.cshtml 查看 Model.Job 的属性并构建编辑控件,类似于 @Html.EditorFor(),但有一些额外的标记。 ScheduledJob.Job 属性的类型为 IJob(接口(interface))。

示例 ScheduledJobsController.cs(简化版):

[HttpPost]
public ActionResult Create(ScheduledJob scheduledJob)
{
    //scheduledJob.Job here is not null, but has only default values
}

当我保存表单时,它正确地解释了对象类型并获得了一个新实例,但是对象的属性没有被设置为它们适当的值。

我还需要做些什么来告诉默认绑定(bind)器接管指定类型的属性绑定(bind)?

最佳答案

This article向我展示了我过度复杂化了模型 Binder 。以下代码有效:

public class InterfaceModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType.IsInterface)
        {
            Type desiredType = Type.GetType(
                EncryptionService.Decrypt(
                    (string)bindingContext.ValueProvider.GetValue("AssemblyQualifiedName").ConvertTo(typeof(string))));
            bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, desiredType);
        }

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

关于c# - 继承自 DefaultModelBinder 的自定义模型绑定(bind)器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16747320/

相关文章:

c# - Cast 有时会抛出异常,但 "as"后跟取消引用不会

c# - 字符串格式说明文字

asp.net-mvc - Entity Framework LINQ 在多个列上连接 5 个表(不可能?!)

c# - FromBody 和 FromHeader 在模型上混合使用,不绑定(bind)所有值

asp.net-mvc - Asp.Net mvc 5 - 如何在 Html.ActionLink() 中将复杂对象作为路由值传递,以便默认模型绑定(bind)器可以映射它?

c# - 在 Windows 服务中,如果 OnStart 被阻止,OnStop 是否会运行?

c# - 使用 T 从 Dictionary<string, object> 转换值

html - 使 HTML5 和 CSS3 网站与旧浏览器兼容?

c# - 更改在Razor MVC中创建区域的方式的最佳方法是什么?

c# - 与 ASP.NET Core 的模型绑定(bind)