ASP.net core 3.1,添加对控制器动作自动绑定的[FromBody]参数的依赖项注入支持

问题描述 投票:0回答:1

我知道如何通过将服务添加到IServiceprovider中来直接注入控制器动作和控制器,然后框架为我自己处理它,在控制器动作的情况下,我可以添加[Microsoft.AspNetCore.Mvc.FromServices]并且它将注入服务采取具体行动。

但是这要求我的控制器明确知道底层参数将需要什么,这是我认为不必要且可能有害的耦合。

我想知道是否有可能接近以下内容:

[HttpPost]
public async Task<ActionResult> PostThings([FromBody]ParameterClassWithInjection parameter) {
  parameter.DoStuff();
...}

public class ParameterClassWithInjection{
  public readonly MyService _myService;
  public ParameterClassWithInjection(IMyService service){ _myService = service;}

  public void DoStuff(){ _myService.DoStuff(); }
}

我只在文档中找到有关自定义模型活页夹的内容。https://docs.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-3.1#custom-model-binder-sample

这显示了如何创建自定义活页夹并让自定义提供程序提供注射。似乎我需要从自动绑定中实现很多样板代码(在每种情况下,这种方法对我来说都绝对不错),以便获得一些依赖注入。

我希望您可以向我指出更好的方向,或者如果这是唯一的选择,请停止我的追求。

c# asp.net-core dependency-injection controller model-binding
1个回答
0
投票

快捷键

如果内容类型是JSON并且您正在使用Newtonsoft.Json,则可以使用自定义合同解析器来deserialize your model with dependency injection

模型绑定

否则,如果需要支持其他内容类型等,则需要采用复杂的方法。

您引用的MSDN文档说明了如何完成自定义模型绑定程序,您不需要这样做。

您需要自定义模型联编程序提供者,而不是模型联编程序。在模型绑定器提供程序中,您可以迭代现有的模型绑定器提供程序,找到当前模型绑定上下文的模型绑定器,然后用您自己的模型绑定器装饰器对其进行装饰,该装饰器可以对模型进行DI。

例如:

public class DependencyInjectionModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        // Get MVC options.
        var mvcOptions = context.Services.GetRequiredService<IOptions<MvcOptions>>();

        // Find model binder provider for the current context.
        IModelBinder binder = null;
        foreach (var modelBinderProvider in mvcOptions.Value.ModelBinderProviders)
        {
            if (modelBinderProvider == this)
            {
                continue;
            }

            binder = modelBinderProvider.GetBinder(context);
            if (binder != null)
            {
                break;
            }
        }

        return binder == null
            ? null
            : new DependencyInjectionModelBinder(binder);
    }
}

// Model binder decorator.
public class DependencyInjectionModelBinder : IModelBinder
{
    private readonly IModelBinder _innerBinder;

    public DependencyInjectionModelBinder(IModelBinder innerBinder)
    {
        _innerBinder = innerBinder;
    }

    public async Task BindModelAsync(ModelBindingContext bindingContext)
    {
        await _innerBinder.BindModelAsync(bindingContext);

        if (bindingContext.Result.IsModelSet)
        {
            var serviceProvider = bindingContext.HttpContext.RequestServices;

            // Do DI stuff.
        }
    }
}

// Register your model binder provider
services.AddControllers(opt =>
{
    opt.ModelBinderProviders.Insert(
        0, new DependencyInjectionModelBinderProvider());
});

这适用于财产注入。

对于构造函数注入,因为模型的创建仍在内部模型绑定器中进行,所以您肯定比该示例需要更多的代码,在这种情况下,我没有尝试过使构造函数注入起作用。

© www.soinside.com 2019 - 2024. All rights reserved.