2017-12-04 12 views
0

Ich muss Modellbindung für eine bestimmte Klasse anpassen Foo, die Erweiterung der normalen Bindung Logik mit einigen zusätzlichen Nachbearbeitung (z. B. bedingt Null Sammlung Felder auf eine leere Sammlung). Ich möchte diese Logik zur Modellbindung hinzufügen, so dass die Ergebnisse für Aktionsfilter usw. verfügbar sind.So erweitern Sie ComplexTypeModelBinder

Der direkteste Ansatz wäre, von ComplexTypeModelBinder abzuleiten und BindModelAsync zu überschreiben. Diese Methode ist jedoch leider nicht virtuell.

Zusammensetzung ist die nächste Alternative. Ich versuche, eine FooModelBinder Klasse zu erstellen, die eine Instanz ComplexTypeModelBinder hat oder erhält. Ich kann jedoch nicht herausfinden, wie man eine ComplexTypeModelBinder injizieren oder auflösen kann. Ist das möglich? Gibt es eine bessere Möglichkeit, die Funktionalität von ComplexTypeModelBinder zu erweitern?

Antwort

0

Ich erkannte schließlich, dass Modellbinder von Modellbinder-Anbietern, nicht über Abhängigkeitsinjektion erhalten werden. Um meine FooModelBinder instanziieren, muss ich eine FooModelBinderProvider erstellen. Und um eine Instanz von ComplexTypeModelBinder für die Komposition zu erhalten, benötigt mein Provider Zugriff auf eine ComplexTypeModelBinderProvider. Mit anderen Worten: Um über einen Modellbinder zu komponieren, müssen Sie auch einen Modellbinderanbieter erstellen.

Hier ist der Anbieter. Beachten Sie, dass wir nicht den genauen Typ des injizierten Providers angeben müssen, da wir einfach die vorhandene Funktionalität eines anderen Modellbinders umschließen.

public class FooModelBinderProvider : IModelBinderProvider 
{ 
    private readonly IModelBinderProvider workerProvider; 

    public FooModelBinderProvider(IModelBinderProvider workerProvider) 
    { 
    this.workerProvider = workerProvider; 
    } 

    public IModelBinder GetBinder(ModelBinderProviderContext context) 
    { 
    if (context == null) 
    { 
     throw new ArgumentNullException(nameof(context)); 
    } 

    if (context.Metadata.ModelType == typeof(Foo)) 
    { 
     return new FooModelBinder(this.workerProvider.GetBinder(context)); 
    } 

    return null; 
    } 
} 

Und hier ist der Binder. Beachten Sie, dass das erste, was wir in BindModelAsync tun, ist Trampolin in den Ordner "Arbeiter".

public class FooModelBinder : IModelBinder 
{ 
    private readonly IModelBinder worker; 

    public FooModelBinder(IModelBinder worker) 
    { 
    this.worker = worker; 
    } 

    public async Task BindModelAsync(ModelBindingContext bindingContext) 
    { 
    await this.worker.BindModelAsync(bindingContext); 
    if (!bindingContext.Result.IsModelSet) 
    { 
     return; 
    } 

    var foo = bindingContext.Result.Model as Foo; 
    if (foo == null) 
    { 
     throw new InvalidOperationException($"Expected {bindingContext.ModelName} to have been bound by ComplexTypeModelBinder"); 
    } 

    // NOW DO SOME INTERESTING POST-PROCESSING 
    } 
} 

Schließlich ist hier, wie die benutzerdefinierten Binder registrieren:

services.AddMvc(options => 
    { 
    var workerProvider = options.ModelBinderProviders.First(p => p.GetType() == typeof(ComplexTypeModelBinderProvider)); 
    options.ModelBinderProviders.Insert(options.ModelBinderProviders.IndexOf(workerProvider), new FooModelBinderProvider(workerProvider)); 
    })