首页 > 解决方案 > 在 ASP.NET Core 中的方法中注入依赖项

问题描述

我有以下场景:我在课堂上注册了一个ICompanyDocumentsService具有单个实现的服务:CompanyDocumentsServiceStartup

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<ICompanyDocumentService, CompanyDocumentService>();
        }

我在很多地方都需要这项服务,而且在构造函数中使用 DI 并不会打扰我。但是,有一个地方我需要在方法中注入它(或者可能在属性中会更好):

            public abstract class CompanyDocumentBase
            {
                public abstract object GetAllProperties(Employee employee, string properties, 
                      CompanyDocumentReferenceData documentReferenceData);
                // blah, blah, lots of Formatting Methods


                private CompanyDocumentService CompanyDocumentService { get; set; } // **inject service here**

                public string GetFormattedEmployeeIndividualEmploymentAgreementNumber(Employee employee, 
                    ICompanyDocumentService companyDocumentService = null) // **optional because 
//inherited class doesn't need to know anything about this service, it concerns only it's result**
                {
                    companyDocumentService = CompanyDocumentService;
                    var test  = 
                       companyDocumentService.GetEmloyeeIndividualEmploymentAgreementNumber(employee.Id);


                    return string.Empty;
                }

            }

有很多继承的类CompanyDocumentBase只关心它的方法结果,如上所述,这就是为什么该参数是可选的,这就是为什么我不需要在构造函数中注入 DI,因此继承类将不需要那个。

 public class JobDescriptionCompanyDocument : CompanyDocumentBase
    {
        public override object GetAllProperties(Employee employee,
            string properties, CompanyDocumentReferenceData documentReferenceData)
        {
            var document = JsonConvert.DeserializeObject<JobDescriptionModel>(properties);

            document.IndividualEmploymentAgreementNumber = GetEmployeeIndividualEmploymentAgreementNumber(employee);

            return document;
        }
    }

有什么简单的方法可以实现这一目标吗?最好不需要安装像 Unity 或 Autofac 这样的单独库。理想的方法是以某种方式将实例CompanyDocumentsService直接放入该属性中,例如:

private CompanyDocumentService CompanyDocumentService => Startup.Services.blah that instance

标签: c#asp.net-coredependency-injection

解决方案


一种 hack 方式(我个人不推荐)是在构建容器之后,您可以解析一个实例IHttpContextAccessor并将其设置为静态类,例如IoC

那你就可以了private CompanyDocumentService CompanyDocumentService => IoC.HttpContextAccessor.HttpContext.RequestServices.GetService()

https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.httpcontext.requestservices?view=aspnetcore-3.1

该接口是一个单例,并提供从静态上下文访问作用域服务。

请注意,您可能必须显式注册 HttpContextAccessor: https ://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-3.1

更新

我会推荐什么

如果您对对象工厂持开放态度,并更改了DocumentBase实例化方式,请尝试创建工厂,并且当您需要 的实例时DocumentBase,仅使用工厂来创建它:

public abstract class CompanyDocumentBase
{
    // Use internal so that access only limited to friendly assembly
    internal CompanyDocumentService CompanyDocumentService { get; set; }
}

// Inject this class to where you need to create an instance of CompanyDocumentBase
public class CompanyDocumentFactory<T> where T : CompanyDocumentBase
{
    private readonly IServiceProvider _services;

    // DI contaiener has implicit IServiceProvider support, when you do this on constructor, it injects service provider of *current* scope
    // If this factory is registered as singleton, you need to use IHttpContextAccessor to use request's service provider in Create method
    // because your DocumentService is scoped.
    public CompanyDocumentFactory(IServiceProvider services)
    {
        _services = services;
    }

    public T Create()
    {
        // Create an instance of document use your current method.
        var instance = new T();
        instance.CompanyDocumentService = _services.GetRequiredService<ICompanyDocumentService>();
        return instance;
    }
}

推荐阅读