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:

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.

 

7 comments

  • ... Posted by Ronald-rademaker Posted 04/23/2012 03:03 PM
    <p>Nice ook #orchardcms zelf sta je lekker bezig<br></p>
  • ... Posted by Sipke Schoorstra Posted 04/23/2012 03:05 PM (Author)

    Je bedoelt dat je ook met Orchard bezig bent?

  • ... Posted by Mobile Apps Development Posted 04/27/2012 06:59 AM [http://mindinventory.com/mobile_apps_dev.php]

    Really,it's very useful code.

  • ... Posted by Leslie Fang Posted 11/28/2012 03:25 PM

    now that you want to inject an concrete class , there is no need to use Ioc , we can instantiate it directly.

  • ... Posted by Leslie Fang Posted 11/28/2012 03:33 PM

    I also want to know if we have two classes derived from the same interface, then when we inject that interface, how can orchard knows to call which class. I write a demo Orchard will inject only one class, it seems the later class override the pre class. I want to know how Orchard do that? Thanks!

  • ... Posted by Leslie Fang Posted 11/28/2012 03:33 PM

    I also want to know if we have two classes derived from the same interface, then when we inject that interface, how can orchard knows to call which class. I write a demo Orchard will inject only one class, it seems the later class override the pre class. I want to know how Orchard do that? Thanks!

  • ... Posted by Jake Bruun Posted 01/30/2013 03:03 AM

    Thanks for the great post Sipke! I've done similar thing with other ioc containers, but it's nice to see the Autofac flavor and how to works with Orchard.

Leave a comment