如何扩展ComplexTypeModelBinder

如何扩展ComplexTypeModelBinder

本文介绍了如何扩展ComplexTypeModelBinder的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要为特定类Foo自定义模型绑定,这涉及通过一些附加的后处理来扩展常规绑定逻辑(例如,有条件地将null集合字段设置为空集合).我想将此逻辑添加到模型绑定中,以便结果可用于操作过滤器等​​.

I need to customize model binding for a particular class Foo that involves extending the normal binding logic with some additional post-processing (e.g., conditionally set null collection fields to an empty collection). I want to add this logic to model binding so that the results are available to action filters, etc.

最直接的方法是从ComplexTypeModelBinder派生并覆盖BindModelAsync.但是,不幸的是,该方法不是虚拟的.

The most direct approach would be to derive from ComplexTypeModelBinder and override BindModelAsync. However, that method is unfortunately not virtual.

下一个替代方法是排版.我正在尝试创建一个具有或获取ComplexTypeModelBinder实例的FooModelBinder类.但是,我不知道如何注入或解析ComplexTypeModelBinder.这可能吗?有没有更好的方法来扩展ComplexTypeModelBinder的功能?

Composition is the next alternative. I'm trying to create a FooModelBinder class that has or obtains an instance of ComplexTypeModelBinder. However, I can't figure out how to inject or resolve a ComplexTypeModelBinder. Is this possible? Is there a better way to extend the functionality of ComplexTypeModelBinder?

推荐答案

我最终意识到,模型联编程序是从模型联编程序提供程序获得的,而不是通过依赖项注入获得的.为了正确地实例化我的FooModelBinder,我需要创建一个FooModelBinderProvider.为了正确获取ComplexTypeModelBinder的实例进行组合,我的提供程序需要访问ComplexTypeModelBinderProvider.换句话说,要组成模型联编程序,还需要组成模型联编程序提供者.

I finally realized that model binders are obtained from model binder providers, not via dependency injection. To properly instantiate my FooModelBinder, I need to create a FooModelBinderProvider. And to properly obtain an instance of ComplexTypeModelBinder for composition, my provider needs access to a ComplexTypeModelBinderProvider. In other words, to compose over a model binder, you also need to compose over a model binder provider.

这里是提供者.请注意,我们不需要指定注入的提供程序的确切类型,因为我们只是包装了另一个模型绑定程序的现有功能.

Here's the provider. Note that we don't need to specify the exact type of the injected provider because we're simply wrapping the existing functionality of another model binder.

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中要做的第一件事是将蹦床插入工人"活页夹中.

And here is the binder. Note that the first thing we do in BindModelAsync is trampoline into the "worker" binder.

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

最后,这是注册自定义资料夹的方法:

Finally, here's how to register the custom binder:

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

这篇关于如何扩展ComplexTypeModelBinder的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-31 10:02