繁体   English   中英

如何在asp.net核心中将依赖注入模型?

[英]How to inject dependencies into models in asp.net core?

假设我有一个控制器动作,如下所示:

[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,你也可以使用丰富的模型。 您需要一个定制的模型绑定器,它将负责注入模型

内置模型绑定器抱怨他们找不到默认的ctor。 因此,您需要一个自定义的。

您可能会找到一个解决类似的问题在这里 ,这种检查的注册服务,以创建模型。

值得注意的是,下面的代码段提供了稍微不同的功能,希望能够满足您的特定需求。 下面的代码预计带有ctor注射的模型。 当然,这些模型具有您可能已定义的常用属性。 这些属性完全按预期填充,因此在使用ctor注射绑定模型时 ,奖励是正确的行为

    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
}

模型类由提供(已注册)服务的活页夹创建,其余模型绑定器提供其常用来源的属性值。

HTH

您是否尝试在configure服务方法中添加服务以提供服务

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM