如何在ASP.NET Core中将依赖项注入模型中? [英] How to inject dependencies into models in asp.net core?

查看:129
本文介绍了如何在ASP.NET Core中将依赖项注入模型中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个类似于以下内容的控制器动作:

Let's say I have a controller action that looks like this:

[HttpPost]
public async Task<IActionResult> Add([FromBody] MyModel model){
    await model.Save();
    return CreatedAtRoute("GetModel", new {id = model.Id}, model);
}

为了使model.Save工作,它需要一些依赖项:

In order to get model.Save to work, it needs some dependencies:

public class MyModel{
    private readonly ApplicationDbContext _context;
    public MyModel(ApplicationDbContext context){
        _context = context;
    }
    public async Task Save(){
        // Do something with _context;
    }
}

截至目前,上下文是MyModel的构造函数中的null.我该如何注射?我知道我可以将服务注入控制器并以这种方式对模型执行操作,但是如果我宁愿使用面向对象的方法而不是贫血的领域模型怎么办?根本不可能吗?

As of right now, context is null in MyModel's constructor. How can I inject it? I'm aware that I can inject services into the controller and perform operations on my model that way, but what if I'd rather use an object-oriented approach than an anemic domain model? Is it simply impossible?

推荐答案

好吧,除了DTO,您还可以使用丰富的模型.您将需要一个自定义的模型活页夹,该活页夹将负责将ctor注入模型.

Well, besides DTO you may also use rich models. You'll need a customized model binder, which will take care of ctor injection into the model.

内置模型联编程序抱怨找不到默认的ctor.因此,您需要一个自定义的.

The built-in model binders complain that they cannot find a default ctor. Therefore you need a custom one.

您可能会在此处找到类似问题的解决方案,它会检查注册的服务以创建模型.

You may find a solution to a similar problem here, which inspects the registered services in order to create the model.

请务必注意,以下片段提供的功能稍有不同,希望可以满足您的特定需求.下面的代码期望带有ctor注入的模型.当然,这些模型具有您可能已定义的常规属性.这些属性将完全按预期填充,因此,奖励是使用ctor注入绑定模型时的正确行为.

It is important to note that the snippets below provide slightly different functionality which, hopefully, satisfies your particular needs. The code below expects models with ctor injections. Of course, these models have the usual properties you might have defined. These properties are filled in exactly as expected, so the bonus is the correct behavior when binding models with ctor injections.

    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;
        }
    }

此资料夹将由以下人员提供:

This binder will be provided by:

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;
    }
}

以下是注册活页夹的方法:

Here's how the binder would be registered:

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());
});

我不太确定新的资料夹是否必须完全在相同的索引处注册,您可以尝试一下.

I'm not quite sure if the new binder must be registered exactly at the same index, you can experiment with this.

最后,这是使用方法:

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
}

由提供(已注册)服务的活页夹创建模型类,其余的模型活页夹从其通常来源提供属性值.

Model class is created by the binder which supplies the (already registered) service, and the rest of the model binders provide the property values from their usual sources.

HTH

这篇关于如何在ASP.NET Core中将依赖项注入模型中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆