Introduction
The Dependency Injection pattern, also known as
Inversion of Control, is one of the most popular design paradigms today. It
enables us to write loosely coupled code, it eliminates tight coupling between
objects to make both the objects and applications that use them more flexible,
reusable, easier to test, and makes it possible to change them at runtime and compile time.
In this article, we will discuss how Dependency Injection
(DI) can help us build a loosely coupled software architecture, and how to
implement DI using Autofac. By the
end of the article, we should be clear about the pattern and how to apply it in
an ASP.NET MVC4 application.
Technology: Visual Studio 2012, .NET Framework 4.5,
ASP.NET MVC4, Entity Framework 5, and
C#.
Background
There are four primary ways in which we can inject dependency
to a class, such as Constructor injection, Setter injection, Property
injection, and Method injection. In this article, I will discuss about Constructor
injection and how to implement DI using Autofac.
Constructor Injection: This is the most common DI. In this methodology we
pass the object reference in the constructor itself. So when the client creates
the object, it passes the object in the constructor. Dependency
Injection is done by supplying the dependency through the class’ constructor
when instantiating that class. The injected component can be used
anywhere within the class.
public class Customer
{
DIDbContext dbContext = new DIDbContext();
public int Create(Customer customer)
{
if (customer != null)
{
dbContext.Customers.Add(customer);
dbContext.SaveChanges();
return 1;
}
return 0;
}
public IEnumerable<customer> GetAllCustomers()
{
return dbContext.Customers.ToList();
}
}
public class CustomerController : Controller
{
Customer customer = null;
public CustomerController()
{
Customer=new Customer();
}
public ActionResult Index()
{
var customers= customer.GetAllCustomers();
return View(customers);
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(Customer customer)
{
customer.Create(customer);
return RedirectToAction("Index");
}
}
The CustomerController
class has a dependency on the Customer
class. In this case, the CustomerController
creates an instance of the Customer
directly inside of the CustomerController
constructor and knows exactly what kind of customer class it’s creating and consuming. It does violate DIP.
To reduce dependency we have to do a couple of steps. Firstly we introduce the Repository layer where we can keep database related functionality such as data insert, modify, and get. Then we introduce the service layer, where we can keep extra logic if we need. For example, if we need to send a mail to the customer or if we need to calculate the total profit from the customer. In this case we can keep mail sending and calculation functionality in the service layer. We can make two abstraction layers between Customer
and CustomerController
. We can use the interface/abstract class to represent the abstractions between the Customer
and CustomerController
.
public interface IRepository<t>
{
int Create(T t);
IEnumerable<t> FindAll();
T FindById(int id);
}
public class CustomerRepository : IRepository<customer>
{
DIDbContext dbContext = new DIDbContext();
public int Create(Customer customer)
{
if (customer != null)
{
dbContext.Customers.Add(customer);
dbContext.SaveChanges();
return 1;
}
return 0;
}
public IEnumerable<customer> FindAll()
{
return dbContext.Customers.ToList();
}
public Customer FindById(int id)
{
return dbContext.Customers.Find(id);
}
}
public interface IService<t>
{
int Create(T t);
IEnumerable<t> FindAll();
T FindById(int id);
void SendMail();
void CalculateTotalProfit();
}
public class CustomerService : IService<customer>
{
private readonly IRepository<customer> _iCustomerRepository;
public CustomerService(IRepository<customer> customerRepository)
{
_iCustomerRepository = customerRepository;
}
public int Create(Customer customer)
{
return _iCustomerRepository.Create(customer);
}
public IEnumerable<customer> FindAll()
{
return _iCustomerRepository.FindAll();
}
public Customer FindById(int id)
{
return _iCustomerRepository.FindById(id);
}
public void SendMail()
{
}
public void void CalculateTotalProfit()
{
}
}
public class CustomerController : Controller
{
private readonly IService<customer> _customerService = null;
public CustomerController(IService<customer> customerService)
{
_customerService = customerService;
}
public ActionResult Index()
{
var customers = _customerService.FindAll();
return View(customers);
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(Customer customer)
{
_customerService.Create(customer);
return RedirectToAction("Index");
}
}</t></t>
Here, we introduce two interfaces, IRepository
and IService
,
to represent the abstraction and to ensure that the CustomerContrller
class only calls methods or properties from the IService
interface because
the CustomerController
class has a dependency on the Service class, and the Customer
class
calls method or properties from the IRepository
interface because the Customer
class
has dependency on the Repository class.
To write loosely couple code we can apply any of these
injections, what injection to be applied will depend on the scenario.
Now we will see how to integrate and implement Autofac with ASP.NET MVC4.
Autofac is an IoC container that provides better integration
for the ASP.NET MVC Framework, and manages dependencies between classes so that
applications
stay easy to change. We
can easily integrate Autofac in our application; for that, first of all, we have
to grab the NuGet
packages. If you're not into NuGet, you can download Autofac from
this site.
Register components with Autofac: Firstly we have to add Autofac assemblies (Autofac.dll,
Autofac.Configuration.dll, and Autofac.Integration.Mvc.dll) to our project. Then we write the following code block in Application_Start()
of Global.asax.cs
that will configure Autofac with ASP.NET MVC 4.
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterType(typeof(CustomerService)).AsImplementedInterfaces();
builder.RegisterType(typeof(CustomerRepository)).AsImplementedInterfaces();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
Credits: Thanks to Rubayat Asirul Bari for reviewing this article and providing many
helpful suggestions.
Conclusion
Hopefully, you’ll be able to use this for your applications and it will make
it a little bit easier to apply Dependency Injection Design Pattern in your
application.