Pregunta Custom Model Binder hereda de DefaultModelBinder


Estoy intentando construir un encuadernador de modelo personalizado para MVC 4 que heredará de DefaultModelBinder. Me gustaría interceptar cualquier interfaz en alguna nivel de enlace e intento de cargar el tipo deseado desde un campo oculto llamado AssemblyQualifiedName.

Esto es lo que tengo hasta ahora (simplificado):

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

Ejemplo de archivo Create.cshtml (simplificado):

@model Models.ScheduledJob

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

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

El parcial anterior _JobParameters.cshtml mira el Model.Jobpropiedades y construye los controles de edición, similar a @Html.EditorFor(), pero con un margen adicional. los ScheduledJob.Job la propiedad es de tipo IJob (interfaz).

Ejemplo ScheduledJobsController.cs (simplificado):

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

Cuando guardo el formulario, interpreta el tipo de objeto correctamente y obtiene una nueva instancia, pero las propiedades del objeto no se establecen en sus valores apropiados.

¿Qué más debo hacer para decirle al encuadernador predeterminado que se haga cargo del enlace de propiedad del tipo especificado?


16
2018-05-25 07:09


origen


Respuestas:


Este artículo me mostró que estaba complicando demasiado la carpeta del modelo. El siguiente código funciona:

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

22
2018-05-25 15:53



Con MVC 4 es fácil sobrescribir los mensajes, si eso es todo lo que necesita en una carpeta de modelo personalizado:

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

Luego crea un archivo de recursos llamado ValidationMessages con entradas como esta:

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

.

Hicimos esto por una falla de cumplimiento. Nuestro análisis de seguridad no le gustó eso javascript la inyección volverá y aparecerá en los mensajes de validación y se ejecutará. Al utilizar esta implementación, anulamos los mensajes predeterminados que devuelven el valor proporcionado por el usuario.


1
2017-11-21 18:45