Services and Dependency

 Introducing Service Layer

 

The service layers the one the controller is going to interact, this service layer can be used for various purposes, and the first one will be to implement CRUD operation.  Since service layer is consuming unit of work we can also make changes to the group of objects and call unit of work save method. The  will be transactional because unit of work will indirectly call to dbcontext savechanges melthod which of course is transactional.

NOTE: The service layer will be used for transactional execution only if  your transaction target only single dbcontext object , if you are targeting multiple dbcontext objects you need to address this issue independently and not covered in this article.

1.          Create Service Layer

Service Layer Interface
//IProductService.cs
public interface IProductService:IDisposable
   {
        void AddProduct(Product product);
        void UpdateProduct(Product product);
        void DeleteProduct(int id);
        List<Product> GetAllProduct();
        Product GetProduct(int productId);
    }
Service layer Implementation
//ProductService.cs
public class ProductService:IProductService
   {
       private readonly  IUnitOfWork _unitOfWork;
     
      public ProductService(IUnitOfWork unitOfWork)
       {
           this._unitOfWork = unitOfWork;
       }

       public void AddProduct(Product product)
       {
           _unitOfWork.ProductRepository.Add(product);
           _unitOfWork.Save();
       }
       public void UpdateProduct(Product product)
       {
           _unitOfWork.ProductRepository.Edit(product);
           _unitOfWork.Save();
       }
       public  void DeleteProduct(int id)
       {
           var org = _unitOfWork.ProductRepository.FindById(id);
           _unitOfWork.ProductRepository.Delete(org);
           _unitOfWork.Save();
       }
       public List<Product> GetAllProduct()
       {
           return _unitOfWork.ProductRepository.GetAll();
       }
       public Product GetProduct(int productId)
       {
           return _unitOfWork.ProductRepository.FindById(productId);
       }

       public void Dispose()
       {
           _unitOfWork.Dispose();
       }
   }

 

2.         Consuming Service Layer at the controller

The ProductController receives service layer as a constructor injection

//ProductController.cs
public class ProductController : Controller
    {
        private readonly IProductService productService;
        public int PageSize = 4;
        //
        // GET: /Product/
     
        public ProductController(IProductService productServiceParam)
        {
          
            this.productService = productServiceParam;
        }
     
        public ViewResult Index(int page=1)
        {
            ProductListViewModel model = new ProductListViewModel
                                             {
                                                 Products = productService.GetAllProduct()
                                                     .OrderBy(p => p.ProductId)
                                                     .Skip((page - 1)*PageSize)
                                                     .Take(PageSize),
                                                 PagingInfo = new PagingInfo
                                                                  {
                                                                      CurrentPage = page,
                                                                      ItemsPerPage = PageSize,
                                                                      TotalItems =
                                                                          productService.GetAllProduct().Count()
                                                                  }




                                             };


            return View(model);
        }


        //
        // GET: /Product/Details/5


        public ActionResult Details(int id = 0)
        {
            Product product = productService.GetProduct(id);
            if (product == null)
            {
                return HttpNotFound();
            }
            return View(product);
        }


        //
        // GET: /Product/Create


        public ActionResult Create()
        {
            return View();
        }


        //
        // POST: /Product/Create


        [HttpPost]
        public ActionResult Create(Product product)
        {
            if (ModelState.IsValid)
            {
               productService.AddProduct(product);
              
                return RedirectToAction("Index");
            }


            return View(product);
        }


        //
        // GET: /Product/Edit/5


        public ActionResult Edit(int id = 0)
        {
            Product product = productService.GetProduct(id);
            if (product == null)
            {
                return HttpNotFound();
            }
            return View(product);
        }


        //
        // POST: /Product/Edit/5


        [HttpPost]
        public ActionResult Edit(Product product)
        {
            if (ModelState.IsValid)
            {
                productService.UpdateProduct(product);
           
                return RedirectToAction("Index");
            }
            return View(product);
        }


        //
        // GET: /Product/Delete/5


        public ActionResult Delete(int id = 0)
        {
            Product product = productService.GetProduct(id);
            if (product == null)
            {
                return HttpNotFound();
            }
            return View(product);
        }


        //
        // POST: /Product/Delete/5


        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(int id)
        {
            productService.DeleteProduct(id);
            return RedirectToAction("Index");
        }


        protected override void Dispose(bool disposing)
        {
            productService.Dispose();
            base.Dispose(disposing);
        }
    }

 

 

Implementing Dependency Injection  

Setting Up Ninject

Since this design favours isoloation of each layer , we need dependency resolver to instantiate and supply dependent objects from one layer to another, for this purpose I have used Ninject dependency resolver.

  1. You have to install Ninject in your MVC project from nugget package
    http://expertester.wordpress.com/2011/08/18/how-to-add-ninject-to-your-project-using-visual-studio-2010-sp1/
  2. Create Dependency Resolver Class  in your MVC project

    Dependancy Resolver
    //NinjectDependencyResolver.cs
    public class NinjectDependencyResolver:IDependencyResolver
        {
            private IKernel kernel;
    
            public NinjectDependencyResolver()
            {
                kernel = new StandardKernel();
                AddBindings();
            }
            public object GetService(Type serviceType)
            {
                return kernel.TryGet(serviceType);
            }
    
            public IEnumerable<object> GetServices(Type serviceType)
            {
                return kernel.GetAll(serviceType);
            }
    
            private void AddBindings()
            {
                kernel.Bind<IUnitOfWork>().To<UnitOfWork>().WhenInjectedInto<ProductService>();
                kernel.Bind<IProductService>().To<ProductService>();
            }
        }


 

 

     3.Register NinjectDependencyResolver in the global.asax

Hooking up the dependency resolver
// Global.asax.cs -Application_Start()
protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            DependencyResolver.SetResolver(new NinjectDependencyResolver());
            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }