Passing Services using Dependency Injection and Factory Pattern in ASP.NET

最后都变了- 提交于 2019-12-30 05:05:10

问题


I am using ASP.NET Core, I know that such Logging mechanism is already provided by the framework, but using this to illustrate my problem.

I am using kind of Factory pattern to build the Logger class, since I don't know the type of logging (because it is stored in DB).

The ILogger Contract

Log(string msg)

Then LoggerFactory will return an ILogger after creating a Logger based on param passed from DB:

public class LoggerFactory
{
    public static Contracts.ILogger BuildLogger(LogType type)
    {
        return GetLogger(type);
    }

//other code is omitted, GetLogger will return an implementation of the related logger

Now, when I need to use the Logger I have to do it in this way:

  public class MyService
{
    private ILogger _logger
    public MyService()
    {
        _logger = LoggerFactory.BuildLogger("myType");
    }

But, I intend to keep my classes without any instantiation, I need to use Constructor DI in MyService and I need to inject all the dependencies on Startup:

    services.AddTransient<Contracts.ILogger, LoggerFactory.BuildLogger("param") > ();

But this will not work this we need to pass a concrete implementation. How to make that work using DI, is there a better approach for implementing that?


回答1:


There are a couple of errors in your approach:

  • Your services depend on the concrete LoggerFactory type which is a Dependency Inversion Principle violation.
  • Doing this extra initialization can make building the object graph unreliable, while injection constructors should be simple.
  • It hides the fact that the ILogger is the real service that your consumer depends upon. This makes the system harder to test, harder to maintain, and complicates object graph analysis.
  • The use of a factory is a smell, since factories are hardly ever the right solution.

Instead, your service should look as follows:

public class MyService
{
    private ILogger _logger;
    public MyService(ILogger logger)
    {
        _logger = logger;
    }
}

This dramatically simplifies all consumers that depend upon ILogger. This also means that getting the right ILogger for MyService becomes a responsibility of the Composition Root, which is the correct place to have this knowledge.

It does mean however that you might need to move away from the built-in DI container of ASP.NET Core to a more feature rich DI library, because the built-in container is not capable of making a context aware registration for ILogger while having the library auto-wire other constructor dependencies as well.

With the ASP.NET Core DI container, you can only hand-wire your services using a delegate. For instance:

services.AddTransient<MyService>(c => new MyService(
    BuildLogger(typeof(MyService).Name),
    c.GetRequiredService<ISomeOtherDependency>(),
    c.GetRequiredService<IYetAnotherOne>());


来源:https://stackoverflow.com/questions/40513388/passing-services-using-dependency-injection-and-factory-pattern-in-asp-net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!