Custom Model Binder inheriting from DefaultModelBinder

倾然丶 夕夏残阳落幕 提交于 2019-11-27 01:08:19

问题


I'm attempting to build a custom model binder for MVC 4 that will inherit from DefaultModelBinder. I'd like it to intercept any interfaces at any binding level and attempt to load the desired type from a hidden field called AssemblyQualifiedName.

Here's what I have so far (simplified):

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);
    }
}

Example Create.cshtml file (simplified):

@model Models.ScheduledJob

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

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

The above partial _JobParameters.cshtml looks at the Model.Job's properties and builds the edit controls, similar to @Html.EditorFor(), but with some extra markup. The ScheduledJob.Job property is of type IJob (interface).

Example ScheduledJobsController.cs (simplified):

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

When I save the form, it interprets the object type correctly and gets a new instance, but the properties of the object are not being set to their appropriate values.

What else do I need to do to this to tell the default binder to take over the property binding of the specified type?


回答1:


This article showed me that I was over-complicating the model binder. The following code works:

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);
    }
}



回答2:


With MVC 4 it is easy to override the messages, if that is all you might need in a custom model binder:

    protected void Application_Start(object sender, EventArgs e)
    {
        //set mvc default messages, or language specifc
        ClientDataTypeModelValidatorProvider.ResourceClassKey = "ValidationMessages";
        DefaultModelBinder.ResourceClassKey = "ValidationMessages";
    }

Then create resource file named ValidationMessages with entries like this:

NAME: FieldMustBeDate 
VALUE: The field {0} must be a date. 
NAME: FieldMustBeNumeric 
VALUE: The field {0} must be a number

.

We did this for a compliance failure. Our security scan did not like that a javascript injection would come back and appear in the Validation Messages and execute. By using this implementation we are overriding the default messages which return the user provided value.



来源:https://stackoverflow.com/questions/16747320/custom-model-binder-inheriting-from-defaultmodelbinder

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!