我知道如何通过将服务添加到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
这显示了如何创建自定义活页夹并让自定义提供程序提供注射。似乎我需要从自动绑定中实现很多样板代码(在每种情况下,这种方法对我来说都绝对不错),以便获得一些依赖注入。
我希望您可以向我指出更好的方向,或者如果这是唯一的选择,请停止我的追求。
快捷键
如果内容类型是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());
});
这适用于财产注入。
对于构造函数注入,因为模型的创建仍在内部模型绑定器中进行,所以您肯定比该示例需要更多的代码,在这种情况下,我没有尝试过使构造函数注入起作用。