如何在asp.net core中注入依赖到模型中
本文关键字:注入 依赖 模型 core asp net | 更新日期: 2023-09-27 18:05:07
假设我有一个这样的控制器动作:
[HttpPost]
public async Task<IActionResult> Add([FromBody] MyModel model){
await model.Save();
return CreatedAtRoute("GetModel", new {id = model.Id}, model);
}
为了让model.Save
工作,它需要一些依赖项:
public class MyModel{
private readonly ApplicationDbContext _context;
public MyModel(ApplicationDbContext context){
_context = context;
}
public async Task Save(){
// Do something with _context;
}
}
目前,在MyModel
的构造函数中,上下文是null
。我怎么注射?我知道我可以将服务注入控制器并以这种方式对模型执行操作,但是如果我宁愿使用面向对象的方法而不是贫血的域模型怎么办?难道根本不可能吗?
您应该考虑使用DTO(数据传输对象)模式重构代码。如果只是
-
MyModel
应该只有一个数据容器->包含属性/计算属性。 -
Save()
方法中的逻辑应该被提取到像ModelRepository
这样的单独类中,它应该知道像ApplicationDbContext
这样的依赖关系:public class ModelRepository { private readonly ApplicationDbContext _context; public ModelRepository(ApplicationDbContext context) { _context = context; } public async Task Save(MyModel model) { // Do something with _context; } }
-
最后,您的控制器应该使用ModelRepository的实例(使用内置DI解决它)来保存您的数据:
[HttpPost] public async Task<IActionResult> Add([FromBody] MyModel model) { await _modelRepository.Save(model); return CreatedAtRoute("GetModel", new {id = model.Id}, model); }
嗯,除了DTO,你还可以使用富模型。您需要一个定制的模型绑定器,它将负责将元素注入到模型中。
内置的模型绑定器抱怨他们找不到默认的actor。因此,您需要定制一个。
您可能会在这里找到一个类似问题的解决方案,它检查已注册的服务以创建模型。
需要注意的是,下面的代码段提供的功能略有不同,希望能满足您的特定需求。下面的代码需要使用注入剂的模型。当然,这些模型具有您可能已经定义的常见属性。这些属性完全按照预期填充,因此在将模型与函数注入绑定时,是正确的行为。 此绑定将由: 活页夹的注册方式如下: 我不太确定新的活页夹是否必须在相同的索引上注册,您可以尝试一下。 最后,你可以这样使用它: 模型类是由提供(已经注册的)服务的绑定器创建的,其余的模型绑定器从它们通常的来源提供属性值。 HTH public class DiModelBinder : ComplexTypeModelBinder
{
public DiModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders) : base(propertyBinders)
{
}
/// <summary>
/// Creates the model with one (or more) injected service(s).
/// </summary>
/// <param name="bindingContext"></param>
/// <returns></returns>
protected override object CreateModel(ModelBindingContext bindingContext)
{
var services = bindingContext.HttpContext.RequestServices;
var modelType = bindingContext.ModelType;
var ctors = modelType.GetConstructors();
foreach (var ctor in ctors)
{
var paramTypes = ctor.GetParameters().Select(p => p.ParameterType).ToList();
var parameters = paramTypes.Select(p => services.GetService(p)).ToArray();
if (parameters.All(p => p != null))
{
var model = ctor.Invoke(parameters);
return model;
}
}
return null;
}
}
public class DiModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null) { throw new ArgumentNullException(nameof(context)); }
if (context.Metadata.IsComplexType && !context.Metadata.IsCollectionType)
{
var propertyBinders = context.Metadata.Properties.ToDictionary(property => property, context.CreateBinder);
return new DiModelBinder(propertyBinders);
}
return null;
}
}
services.AddMvc().AddMvcOptions(options =>
{
// replace ComplexTypeModelBinderProvider with its descendent - IoCModelBinderProvider
var provider = options.ModelBinderProviders.FirstOrDefault(x => x.GetType() == typeof(ComplexTypeModelBinderProvider));
var binderIndex = options.ModelBinderProviders.IndexOf(provider);
options.ModelBinderProviders.Remove(provider);
options.ModelBinderProviders.Insert(binderIndex, new DiModelBinderProvider());
});
public class MyModel
{
private readonly IMyRepository repo;
public MyModel(IMyRepository repo)
{
this.repo = repo;
}
... do whatever you want with your repo
public string AProperty { get; set; }
... other properties here
}
您是否尝试在configure services方法中添加服务来提供服务