【问题标题】:How do I use custom model binder that supports dependency injection in ASP.NET Core?如何在 ASP.NET Core 中使用支持依赖注入的自定义模型绑定器?
【发布时间】:2019-07-25 16:37:19
【问题描述】:

我正在尝试在 MVC 中使用我想从我的 IoC 容器中解析的自定义模型绑定器。我遇到的问题是我在添加 MVC 服务时无法访问我的容器,因为我的容器尚未构建(我需要在构建容器之前添加 MVC)。感觉就像鸡/蛋的问题,我确定我缺少一个简单的解决方案。

例子:

services.AddMvc().AddMvcOptions(options =>
{
     options.ModelBinders.Add(serviceProvider.Resolve<CustomModelBinder>());
});

我的自定义模型绑定器如下所示:

public class CustomModelBinder : IModelBinder
{
    private IServiceProvider serviceProvider;

    public CustomModelBinder(IServiceProvider serviceProvider)
    {
        this.serviceProvider = serviceProvider;
    }

    public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
    {
        var model = serviceProvider.GetService(bindingContext.ModelType);
        bindingContext.Model = model;

        var binder = new GenericModelBinder();
        return binder.BindModelAsync(bindingContext);
    }
}

【问题讨论】:

    标签: c# asp.net-core dependency-injection autofac model-binding


    【解决方案1】:

    这里的帖子:https://github.com/aspnet/Mvc/issues/4167

    要直接回答您的问题,请使用:

    bindingContext.OperationBindingContext.ActionContext.HttpContext.RequestServices
    

    附带说明,您还可以选择使用[FromServices] 为您解决问题。

    【讨论】:

      【解决方案2】:

      您可以使用IConfigureOptions 来配置带有依赖注入的选项,而不是使用在模型绑定器中检索所需服务的服务定位器模式。这允许您延迟选项的配置,直到构建依赖注入容器。

      这是一个依赖于ICustomService的模型绑定器:

      class CustomModelBinder : IModelBinder
      {
          private readonly ICustomService customService;
      
          public CustomModelBinder(ICustomService customService) => this.customService = customService;
      
          public Task BindModelAsync(ModelBindingContext bindingContext)
          {
              // Use customService during model binding.
          }
      }
      

      您需要此模型绑定器的提供程序:

      class CustomModelBinderProvider : IModelBinderProvider
      {
          private readonly ICustomService customService;
      
          public CustomModelBinderProvider(ICustomService customService) => this.customService = customService;
      
          public IModelBinder GetBinder(ModelBinderProviderContext context)
          {
              // Return CustomModelBinder or null depending on context.
              return new CustomModelBinder(customService);
          }
      }
      

      通常,您会使用如下代码在Startup 中添加模型绑定器提供程序:

      services.AddMvc().AddMvcOptions(options =>
      {
          options.ModelBinderProviders.Add(new CustomModelBinderProvider(customService));
      });
      

      但是,正如您所指出的,这是不可能的。在配置系统时,您无法解析 customService。这个问题的一般解决方案是使用IConfigureOptions 和上面的代码来配置选项,但还有一个额外的好处是能够使用依赖注入:

      class CustomModelBinderConfigureMvcOptions : IConfigureOptions<MvcOptions>
      {
          private readonly ICustomService customService;
      
          public CustomModelBinderConfigureMvcOptions(ICustomService customService) => this.customService = customService;
      
          public void Configure(MvcOptions options)
              => options.ModelBinderProviders.Add(new CustomModelBinderProvider(customService));
      }
      

      这个类必须添加到Startup的容器中

      services.AddSingleton<IConfigureOptions<MvcOptions>, CustomModelBinderConfigureMvcOptions>();
      

      您现在可以使用具有依赖关系的模型绑定器。

      【讨论】:

      • 我在 CreateHostBuilder(args).Build().Run() 上遇到错误,尝试激活“CustomModelBinderConfigureMvcOptions”时无法解析“IMyinterface”类型的服务。
      【解决方案3】:

      对于 ASP.NET Core 2.2,这应该适用于 DI:

      public class CustomModelBinder : IModelBinder
      {
          public Task BindModelAsync(ModelBindingContext bindingContext)
          {
              // dependency injection
              var model = bindingContext.HttpContext.RequestServices.GetService(bindingContext.ModelType);
      
              // other changes...
      
              bindingContext.Result = ModelBindingResult.Success(model);
      
              return Task.CompletedTask;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2012-06-06
        • 1970-01-01
        • 2017-01-31
        • 1970-01-01
        • 2012-02-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-03
        相关资源
        最近更新 更多