Внедрение зависимости в методе в ASP. NET Core - PullRequest
1 голос
/ 16 марта 2020

У меня есть следующий сценарий: я получил услугу ICompanyDocumentsService с одной реализацией CompanyDocumentsService, которую я регистрирую в своем Startup классе:

 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 или Autofa c. В идеале было бы так или иначе получить экземпляр CompanyDocumentsService непосредственно в это свойство, что-то вроде:

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

1 Ответ

1 голос
/ 16 марта 2020

Один из способов взлома (лично я бы не рекомендовал его) - после сборки контейнера вы можете разрешить экземпляр IHttpContextAccessor и установить для него класс * stati c, например 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

Интерфейс является одноэлементным и обеспечивает доступ к сервисам с заданной областью из статического c контекста .

Обратите внимание, что вам, возможно, придется явно зарегистрировать HttpContextAccessor: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-3.1

ОБНОВЛЕНИЕ

What I ' рекомендую

Если вы открыты для объектных фабрик и изменили способ создания экземпляра 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;
    }
}
...