Autofac.Module
Although Autofac is not really part of Orchard's public API, it does come in handy when you need to customize how some of your classes are created and managed by Autofac.
In general, when you write your own classes that are injectable, you would take the following steps:
- Define an interface that derives from IDependency;
- 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:
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:
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.
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).
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.