You might be starting a new project using OpenAccess ORM and wondering how to implement dependency injection to prevent hard-coded dependencies and enable the possibility of changing them at run-time. Well it’s not that hard specially with the new Dependency Injection Framework available today where all you need to do is get them on nuget, reference it to your project then your all good to go.
I will explain this in the easiest way possible and I will start by explaining my sample architecture first by defining the different layers I used. We will also concentrate on one database table called Departments. Lets start.
Lest say your architecture is simply composed of 4 layers for now namely:
- Domain – This contains the models of your business objects.
- Infrastructure – This contains the abstraction layer you put on your data access layer.
- Web – Which is your presentation layer.
- Tests – I think I don’t need to explain this.
For the Domain we don’t need coding as it’s all generated for you by Telerik so let’s go straight ahead to the Infrastructure Layer. Lets concentrate on 4 files:
Repository.cs – This contains your generic repository codes to extract and or process information from your domain
using EmployeesDemo.Domain; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Web; namespace EmployeesDemo.Infrastructure.Repositories { public abstract class Repository<T> : IDisposable, IRepository<T> where T : class { protected IEntitiesModelUnitOfWork Context { get; private set; } protected Repository(IEntitiesModelUnitOfWork context) { this.Context = context; } public IList GetAll() { return this.Context.GetAll().ToList(); } public T Find(Expression<Func<T, bool>> predicate) { return this.Context.GetAll().FirstOrDefault(predicate); } public void Add(T order) { this.Context.Add(order); } public void Remove(T order) { this.Context.Delete(order); } public void Dispose() { this.Context = null; } } }
IRepository.cs – The interface for you Repository.cs
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Web; namespace EmployeesDemo.Infrastructure.Repositories { public interface IRepository<T> where T : class { T Find(Expression<Func<T, bool>> predicate); void Add(T order); IList GetAll(); void Remove(T order); } }
DepartmentRepository.cs – This contains abstraction only for the Department Entity, if it’s a generic method it should be placed in the Repository.cs
using EmployeesDemo.Domain; using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace EmployeesDemo.Infrastructure.Repositories { public class DepartmentRepository : Repository<Department>, IDepartmentRepository { public DepartmentRepository(IEntitiesModelUnitOfWork context) : base(context) { } public Department GetBy(string name) { return this.Context.GetAll<Department>().FirstOrDefault(x => x.Name == name); } } }
IDepartmentRepository.cs – This is the interface for DepartmentRepository.
using EmployeesDemo.Domain; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EmployeesDemo.Infrastructure.Repositories { public interface IDepartmentRepository : IRepository<Department> { Department GetBy(string name); } }
Now lets go to the presentation layer, first we define a view model which eventually we ill be using later on our Controller and Views.
DepartmentsViewModel.cs – Basically a model for a list of all Departments
using EmployeesDemo.Domain; using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace EmployeesDemo.Web.Models { public class DepartmentsViewModel { public DepartmentsViewModel() { this.Departments = new List<Department>(); } public IList<Department> Departments { get; set; } } }
DepartmentViewModel.cs – A model used for an individual Department
using EmployeesDemo.Domain; using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace EmployeesDemo.Web.Models { public class DepartmentViewModel { public string Name { get; set; } public string Description { get; set; } } }
DepartmentService.cs – Now this is the class used to communicate with your repository
using EmployeesDemo.Web.Models; using EmployeesDemo.Infrastructure.Repositories; using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace EmployeesDemo.Web.Services { public class DepartmentService { private readonly IDepartmentRepository departmentRepository; public DepartmentService( IDepartmentRepository departmentRepository) { this.departmentRepository = departmentRepository; } public DepartmentsViewModel GetAll() { return new DepartmentsViewModel { Departments = departmentRepository.GetAll().ToList() }; } public DepartmentViewModel GetBy(string name) { var department = departmentRepository.GetBy(name); return new DepartmentViewModel { Name = department.Name }; } } }
HomeController.cs – This controls Home View and it is here we will use the service we need, in this case the Department Service. Once a constructor is created we can now use the services on the code.
using EmployeesDemo.Web.Services; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace EmployeesDemo.Web.Controllers { public class HomeController : Controller { public DepartmentService departmentService; public HomeController( DepartmentService departmentService) { this.departmentService = departmentService; } public ActionResult Index() { ViewBag.Message = "Welcome to ASP.NET MVC!"; var technologyDepartment = departmentService.GetBy("Technology"); var allDepartment = departmentService.GetAll(); return View(); } } }
But not run it yet, though it will compile error free you will get this error on runtime.
Server Error in ‘/’ Application.
No parameterless constructor defined for this object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.MissingMethodException: No parameterless constructor defined for this object.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below. |
Why??? This is because by default ASP.NET MVC requires that the controllers have a public parameter-less constructor, in turn creating an instance of the controller. So in our example our constructor requires the DepartmentService instance and we need something to pass such an instance to our controller. This is now where you need dependency injection framework, up to you what you use there are lots of options like Unity, Castle.Windsor, Autofac, StructureMap etc. I had used Castle.Windsor before and had no complaints with it but for now lets use Ninject.
Now to do that first you need to download it in nuget just search for Ninject and install the Ninject.MVC3 first, I said that because this makes it easier as its dependencies are the other two so it installs them as well automatically
Once installed we need to create a NinjectModule and let ninject glue it together for you. What I had done is create a folder called IoC, in that folder we create a class called ControllerModule
Now let’s do the binding
using EmployeesDemo.Domain; using EmployeesDemo.Infrastructure.Repositories; using EmployeesDemo.Web.Services; using Ninject.Modules; using Ninject.Web.Common; using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace EmployeesDemo.Web.IoC { public class ControllerModule : NinjectModule { public override void Load() { this.Bind<IEntitiesModelUnitOfWork>().To<EntitiesModel>() .InRequestScope() .WithConstructorArgument("connectionId", "TestingDatabaseConnection"); this.Bind<IDepartmentRepository>().To<DepartmentRepository>() .InRequestScope(); this.Bind<DepartmentService>().To<DepartmentService>() .InRequestScope(); } } }
Now were done with the binding lets modify our Global.asax so everything registers on ApplicaitonStart. First lets inherit NinjectHttpApplication and replace the default HttpApplication
Next is replacing the
void Application_Start()
with
override void OnApplicationStarted()
then call
base.OnApplicationStarted();
We also need to override the CreateKernel method of the NinjectHttpApplication
protected override IKernel CreateKernel() { IKernel kernel = new StandardKernel(); kernel.Load(Assembly.GetExecutingAssembly()); return kernel; }
Finally since we created it on Global.asax we don’t need the ninject generated codes called NinjectWebCommon.cs which was created in the App_Start folder so delete them
Now you’re good to go, run your application then see the results