使用autofac将构造函数注入基类 [英] Constructor injection into a base class using autofac

查看:712
本文介绍了使用autofac将构造函数注入基类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个抽象的基本控制器,该控制器具有一个构造函数,希望在构造控制器时由autofac填充。

I have an abstract base controller which has a constructor I hoped would be populated by autofac when the controllers were built.

public abstract class BaseController : Controller
{
    protected ILogger { get; private set; }

    protected BaseController()
    {
    }

    protected BaseController(ILogger logger)
    {
        Logger = logger;
    }
}

当我从中派生控制器时,这似乎不起作用

This doesnt seem to work when I derive a controller from it.

只有当我从控制器中显式调用构造函数时,我才能使它起作用。

I can only get this to work when I explicitly call the constructor explicitly from the controller. Is this the correct way to do this?

public class PublicController : BaseController
{
    public PublicController()
    {
    }

    public PublicController(ILogger logger) : base(logger)
    {

    }
}

此外,使用mvc集成程序集,似乎还没有一种为其他类共享容器的方法自己解决。我在某处读到不鼓励这样做,为什么不这样做呢?这是否只是为了消除任何单个ioc框架的依赖性?构造函数注入是唯一的方法来填充依赖关系。

Also, using the mvc intergration assembly, there doesnt seem to be a way to share the container for other classes to do their own resolving. I read somewhere that this is not encouraged, why not? Is this just to decouple the dependancy of any single ioc framework? Is constructor injection the only way to populate dependances down the heirachy.

谢谢

推荐答案

显式调用基类构造函数是在C#中使用构造函数注入实现此目的的唯一方法。看来您应该从 BaseController PublicController 中删除​​无参数的构造函数,因为在记录程序被使用时绝对不应该调用它们。

Calling the base class constructor explicitly is the only way to do this using constructor injection in C#. It looks like you should remove the parameterless constructors from BaseController and PublicController as they should never actually be called when a logger is available.

将依赖项注入基本控制器的问题是使用ASP.NET MVC和IoC的常见问题。有几种选择/思想流派。

The problem of injecting dependencies into a base controller is a common one using ASP.NET MVC and IoC. There are several options/schools of thought.

1。)使用汇总服务。为了使派生类的构造函数保持简单,请创建一个服务,以公开或委托基础控制器所需的所有不同服务(例如 IBaseControllerDependencies 或类似服务。)然后传递此服务就像在这里使用 ILogger 一样,将其添加到 BaseController

1.) Use aggregate services. To keep derived class constructors simple, create a single service that exposes or delegates to all the different services needed by the base controller (e.g. IBaseControllerDependencies or similar.) Then pass this one service to the BaseController just as you are doing with ILogger here.

根据您的应用程序和所使用的基类的数量,有各种优点/缺点。 Google的 Autofac聚合服务以了解更多信息。

There are various pros/cons depending on your application and the number of base classes you're using. Google for 'Autofac aggregate services' to see more on this.

2。)使用属性注入。将基类上的 ILogger 属性公开,并使用以下命令配置容器:

2.) Use property injection. Make the ILogger property on your base class public, and configure the container using:

builder.RegisterControllers().PropertiesAutowired();

在Autofac中,属性注入并不是真正的首选技术。构造函数的角色 可以接受依赖关系,而可写属性通常被视为代码的味道,因此Autofac并未针对这种情况进行真正的优化。缺点之一是不应经常被注入的可写属性被错误地插入,产生了奇怪的后果。

Property injection isn't really a preferred technique in Autofac. The constructor's role is to accept dependencies, while writeable properties are often seen as a code smell, so Autofac doesn't really optimise for this case. One of the drawbacks is that writeable properties that shouldn't be injected often are mistakenly, with odd consequences.

3。)重构基本控制器各种动作过滤器的功能。 Autofac可以将动作过滤器注入MVC​​动作调用管道。因此,筛选器可以采用基类上的依赖项,并且可以以交叉方式应用相同的关注点。有关更多信息,请参见 ExtensibleActionInvoker .InjectActionInvoker()指向所需的信息。

3.) Refactor base controller functionality into various action filters. Autofac can inject action filters into the MVC action invocation pipeline. Thus the filters can take the dependencies that were on the base class, and the same concerns might be applied in a cross-cutting way. More info on this out on the web, ExtensibleActionInvoker and .InjectActionInvoker() point to the info you'd need. Not always possible with all concerns.

4,也是第二个问题的答案。)使用 DependencyResolver.Current中的服务位置来解析基本控制器依赖项。

4, also the answer to your second question.) Resolve base controller dependencies using service location from DependencyResolver.Current.

var logger = DependencyResolver.Current.GetService<ILogger>();

不鼓励这样做的原因是,它会使生成的应用程序更难以理解,因为它不是通过在一个位置(构造函数)查看,可以更长久地查看组件所依赖的服务。要确定在使用特定组件之前必须在容器中配置什么,必须查看组件的整个代码库以查找 GetService()调用。

The reason this isn't encouraged is that it makes the resulting application harder to understand because it is no longer possible to see what services a component depends upon by looking in one place (the constructor.) To determine what must be configured in the container before a particular component can be used, one has to look at the entire codebase of the component to find the GetService() calls. A noticeable impediment when unit testing.

希望这会有所帮助,我知道一点脑筋急转弯:)其他人可能可以在其中添加更多的想法。

Hope this helps, bit of a brain dump I know :) Others can probably add some more ideas to these.

这篇关于使用autofac将构造函数注入基类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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