请注意,本站并不支持低于IE8的浏览器,为了获得最佳效果,请下载最新的浏览器,推荐下载 Chrome浏览器
欢迎光临。交流群:166852192

Autofac.Module


In general, when you write your own classes that are injectable, you would take the following steps:
  1. Define an interface that derives from IDependency;
  2. Define a class that implements your interface
 
However, in certain cases, you may want to inject concrete classes directly into your constructor instead of an interface. One example might be when you implement the Command Pattern. You would generally have multiple classes that ultimately implement some ICommand interface. Next, consider having a controller that has a dependency on some command, e.g. SaveCustomerCommand. One solution could be to create a specific interface for each command, which would be perfectly fine (and perhaps even preferrable for unit testing classes that depend on these commands). But let's say that for some reason you don't want to write these interfaces. How would you be able to inject an UpdateCustomerCommand or a SaveCustomerCommand?
The answer is to tell Autofac about it!
In order to do so, we write a class the derives from Autofac.Module and override its Load method.
The Load method takes a single argument of type ContainerBuilder, which is all we need to register new types.
Let's see an example.
First, let's define an ICommand interface and two implementing classes: SaveCustomerCommand and CreateOrderCommand:
一般来说,当你编写自己的注入类时,你需要执行以下步骤:
定义从IDependency派生的接口;
定义一个实现你的接口的类
但是,在某些情况下,您可能想要将具体类直接注入到构造函数中,而不是接口。一个示例可能是在实现命令模式时。你通常会有多个类,最终实现一些ICommand接口。接下来,考虑具有对某些命令具有依赖性的控制器,例如SaveCustomerCommand。一个解决方案可能是为每个命令创建一个特定的接口,这将是完全精细(或许甚至更喜欢依赖于这些命令的单元测试类)。但是让我们说,由于某种原因你不想写这些接口。您将如何注入UpdateCustomerCommand或SaveCustomerCommand?
答案是告诉Autofac它!
为了这样做,我们写一个类从Autofac.Module派生并重写它的Load方法。
Load方法接受ContainerBuilder类型的一个参数,这是我们需要注册新类型的。
让我们看一个例子。
首先,我们定义一个ICommand接口和两个实现类:SaveCustomerCommand和CreateOrderCommand:
Commands/ICommand.cs:
public interface ICommand {
        void Execute();
    }
 
Commands/SaveCustomerCommand.cs:
public class SaveCustomerCommand : ICommand {
        private readonly ICommerceServices _services;
 
        // Commands support DI just like any other class        
        public SaveCustomerCommand(ICommerceServices services) {
            _services = services;
        }
 
        public void Execute() {
            // perform some action here, e.g. create a new customer or update an existing one        }
    }
 
Commands/CreateOrderCommand.cs:
public class CreateOrderCommand : ICommand    {
        private readonly ICommerceServices _services;
 
        // Commands support DI just like any other class        
        public CreateOrderCommand(ICommerceServices services)
        {
            _services = services;
        }
 
        public void Execute()
        {
            // perform some action here, e.g. create a new order        }
    }
 
The ICommerceService interface is just a sample interface without any members:
ICommerceService接口只是一个没有任何成员的示例接口: 
Services/ICommerceServices.cs:
public interface ICommerceServices {}
 

Next, we'll define two controllers where one controller takes a dependency on SaveCustomerCommand while the other takes a dependency on CreateOrderCommand.
 接下来,我们将定义两个控制器,其中一个控制器依赖于SaveCustomerCommand,而另一个控制器依赖于CreateOrderCommand。
Controllers/CustomerController.cs:
public class CustomerController : Controller {
        private readonly SaveCustomerCommand _saveCommand;
 
        // Inject a SaveCustomerCommand        
        public CustomerController(SaveCustomerCommand saveCommand) {
            _saveCommand = saveCommand;
        }
 
        public ActionResult CreateCustomer() {
            _saveCommand.Execute();
            return Content("Customer created");
        }
    }
 
Controllers/OrderController.cs:
using System.Web.Mvc;using Orchard.Docs.Misc.Commands; 
namespace Orchard.Docs.Misc.Controllers {
    public class OrderController : Controller {
        private readonly CreateOrderCommand _createOrderCommand;
 
        // Inject a CreateOrderCommand        
        public OrderController(CreateOrderCommand createOrderCommand) {
            _createOrderCommand = createOrderCommand;
        }
 
        public ActionResult CreateOrder() {
            _createOrderCommand.Execute();
            return Content("Order created");
        }
    }
}
 
Now, in order to allow this to work, we need to tell Autofac how to give us these command types.
Create another class that derives from Autofac.Module (note that you need to add a reference to the Autofac assembly, which is located in the "Lib" folder that comes with Orchard's source).
现在,为了让这个工作,我们需要告诉Autofac如何给我们这些命令类型。
创建从Autofac.Module派生的另一个类(请注意,您需要添加对Autofac程序集的引用,该程序集位于Orchard源代码中的“Lib”文件夹中)。
ModuleBuilders/CommandsModule.cs:
using Autofac;using Autofac.Features.ResolveAnything; 
public class CommandsModule : Module {
    protected override void Load(ContainerBuilder builder)
    {
        // Configure Autofac to create a new instance of any type that implements ICommand when such type is requested        
        builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource(t => t.IsAssignableTo<ICommand>()));
    }
}
 
Basically, we're registering a new RegisterSource of type AnyConcreteTypeNotAlreadyRegisteredSource, passing in a predicate of which types to register. We're telling it to register all types that implement ICommand by taking advantage of the IsAssignableTo<T> extension method that comes with Autofac.

The effect: whenever we request a type that implements ICommand, Autofac will provide in instance of that type for us.
基本上,我们注册了一个新的AnyConcreteTypeNotAlreadyRegisteredSource类型的RegisterSource,传入要注册的类型的谓词。 我们要通过利用Autofac附带的IsAssignableTo <T>扩展方法来注册实现ICommand的所有类型。


效果:每当我们请求一个实现ICommand的类型时,Autofac将为我们提供该类型的实例。



作者原创内容不容易,如果觉得内容不错,请点击右侧“打赏”,赏俩给作者花花,也算是对作者付出的肯定,也可以鼓励作者原创更多更好内容。
更多详情欢迎到QQ群 166852192 交流。