2017-12-04 22 views
0

일부 추가 사후 처리 (예 : 조건부로 null 컬렉션 필드를 빈 컬렉션으로 설정)로 일반 바인딩 논리를 확장하는 것과 관련된 특정 클래스 Foo에 대한 모델 바인딩을 사용자 정의해야합니다. 이 논리를 모델 바인딩에 추가하여 결과가 액션 필터 등에서 사용 가능하도록하십시오.ComplexTypeModelBinder를 확장하는 방법

가장 직접적인 접근 방식은 ComplexTypeModelBinder에서 파생되고 BindModelAsync을 무시하는 것입니다. 그러나이 방법은 불행히도 가상이 아닙니다.

작곡이 다음 대안입니다. 난 ComplexTypeModelBinder의 인스턴스를 가지고 있거나 얻고있는 FooModelBinder 클래스를 만들려고합니다. 그러나 ComplexTypeModelBinder을 삽입하거나 해결하는 방법을 알 수 없습니다. 이것이 가능한가? ComplexTypeModelBinder의 기능을 확장하는 더 좋은 방법이 있습니까?

답변

0

필자는 모델 바인더가 종속성 삽입을 통하지 않고 모델 바인더 공급자로부터 얻어 졌다는 것을 알게되었습니다. FooModelBinder을 올바르게 인스턴스화하려면 FooModelBinderProvider을 만들어야합니다. 그리고 구성을 위해 ComplexTypeModelBinder의 인스턴스를 제대로 얻으려면 내 제공자가 ComplexTypeModelBinderProvider에 액세스해야합니다. 즉, 모델 바인더를 통해 작성하려면 모델 바인더 공급자를 통해 작성해야합니다.

여기 제공자가 있습니다. 우리는 다른 모델 바인더의 기존 기능을 단순히 래핑하기 때문에 삽입 된 공급자의 정확한 유형을 지정할 필요가 없습니다.

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

그리고 여기에 바인더가 있습니다. 우리가 BindModelAsync에서 수행하는 첫 번째 작업은 "작업자"바인더에 대한 트램펄린입니다.

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

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

마지막으로, 여기에 사용자 정의 바인더를 등록하는 방법