it-swarm.com.de

Benutzerdefinierte Modellbinder, die von DefaultModelBinder erben

Ich versuche, eine benutzerdefinierte Modellmappe für MVC 4 zu erstellen, die von DefaultModelBinder erbt. Ich möchte, dass es alle Schnittstellen auf der any - Bindungsebene abfängt und versucht, den gewünschten Typ aus einem versteckten Feld namens AssemblyQualifiedName zu laden.

Folgendes habe ich bisher (vereinfacht):

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

Beispieldatei Create.cshtml (vereinfacht):

@model Models.ScheduledJob

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

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

Der obige Teilcode von _JobParameters.cshtml untersucht die Eigenschaften von Model.Job und erstellt die Bearbeitungssteuerelemente, ähnlich wie @Html.EditorFor(), jedoch mit zusätzlicher Markup-Funktion. Die ScheduledJob.Job-Eigenschaft ist vom Typ IJob (Schnittstelle).

Beispiel ScheduledJobsController.cs (vereinfacht):

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

Wenn ich das Formular speichere, interpretiert es den Objekttyp korrekt und ruft eine neue Instanz auf, aber die Eigenschaften des Objekts werden nicht auf die entsprechenden Werte festgelegt.

Was muss ich noch tun, damit der Standardordner die Eigenschaftsbindung des angegebenen Typs übernimmt?

17
Albert Bori

Dieser Artikel hat mir gezeigt, dass ich den Musterordner sehr verkompliziert habe. Der folgende Code funktioniert:

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);
    }
}
23
Albert Bori

Mit MVC 4 können Sie die Meldungen leicht überschreiben, wenn Sie dies in einem benutzerdefinierten Modellordner tun könnten:

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

Dann erstellen Sie eine Ressourcendatei mit dem Namen ValidationMessages mit folgenden Einträgen:

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

.

Wir haben dies für einen Compliance-Fehler getan. Unser Sicherheitsscan hat es nicht gefallen, dass eine javascript-Injektion zurückkommt und in den Validierungsnachrichten erscheint und ausgeführt wird. Mit dieser Implementierung überschreiben wir die Standardnachrichten, die den vom Benutzer angegebenen Wert zurückgeben.

1
Joe Kahl