Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do implement Unit of Work, Repository and Business Logic in ASP MVC?

I currently been assigned to a asp mvc project using entity framework. This will be a Line of Business application. I want to develop this app using repository and unit of work pattern. I'm new to this pattern (and new to .net too) and i am having a problem in understanding the pattern and how to implement it.

I have read numerous articles and i think this is how my application should be

Entity Framework -> Repository -> Unit of Work -> Client (Asp MVC)

I attach some code from this article http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

using System;
using ContosoUniversity.Models;

namespace ContosoUniversity.DAL
{
    public class UnitOfWork : IDisposable
    {
        private SchoolContext context = new SchoolContext();
        private GenericRepository<Department> departmentRepository;
        private GenericRepository<Course> courseRepository;

        public GenericRepository<Department> DepartmentRepository
        {
            get
            {

                if (this.departmentRepository == null)
                {
                    this.departmentRepository = new GenericRepository<Department>(context);
                }
                return departmentRepository;
            }
        }

        public GenericRepository<Course> CourseRepository
        {
            get
            {

                if (this.courseRepository == null)
                {
                    this.courseRepository = new GenericRepository<Course>(context);
                }
                return courseRepository;
            }
        }

        public void Save()
        {
            context.SaveChanges();
        }

        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    context.Dispose();
                }
            }
            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}

Unit of Work will have repositories and will create DBContext upon creation

So controller will create Unit of Work upon creation. To Show data i will use this code

var department = UoW.departmentRepository.Find(1);
return View(department);

and when client click save button, i will run this code

UoW.departmentRepository.Update(department);
UoW.Save();

My question:

  1. What if it takes hours from data retrieval until the client click save button. From what i know, we have to keep context as short as possible.

  2. Where should i put business logic? Do i put it in repository? So i would call UoW.departmentRepository.Validate(department) before save. But then, what if i need to validate entity which relate to other entity. Do i call UoW.departmentRepository.Validate(course, department)?

Is there a complete sample project for this kind of application?

EDIT

As Ant P adviced, i need to add another layer to put my business logic.

This is what i have come so far

Unit Of Work:

public class UnitOfWork : IDisposable
{
    private DBContext _context = new DBContext();

    public DBContext Context 
    {
      get 
      {
        return this._context;
      }
    }

    public void Save()
    {
        _context.SaveChanges();
    }

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                context.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

Business Logic:

public class SalesBusinessLogic : IDisposable
{
    private ICustomerRepository _customerRepo;
    private ISalesRepository _salesRepo;
    private UnitOfWork _uow;

    public SalesBusinessLogic(UnitOfWork uow)
    {
      this._uow = uow;
    }

    public ICustomerRepository CustomerRepo
    {
        get
        {

            if (this._customerRepo == null)
            {
                this._customerRepo = new CustomerRepository(this._uow);
            }
            return this._customerRepo;
        }
    }

    public ISalesRepository SalesRepo
    {
        get
        {

            if (this._salesRepo == null)
            {
                this._salesRepo = new SalesRepository(this._uow);
            }
            return this._salesRepo;
        }
    }

    public bool Validate(Sales sales)
    {
      //this is where validation performed
      return true;
    }
}

Controller:

public SalesController : Controller
{
    private UnitOfWork _uow = new UnitOfWork();
    private SalesBusinessLogic _bl = new SalesBusinessLogic(this._uow);

    public ActionResult Index()
    {
        var sales = _bl.SalesRepo.Find(1);
        sales.CustomerID = 1;
        if _bl.Validate(sales)
        {
          _bl.SalesRepo.Update(sales);
          _uow.Save();
        }
        return View(sales);
    }    
}

Here UnitOfWork act only as provider of dbcontext, which will be consumed by business logic and repository. Repository will be in BusinessLogic class.

Server side validation will be handled by BusinessLogic and client side validation will be handled by viewmodel in Web Layer.

My only concern is that dbcontext in UnitofWork is publicly accessible.

Am i in the right direction here?

like image 583
Reynaldi Avatar asked Sep 19 '13 02:09

Reynaldi


1 Answers

What if it takes hours from data retrieval until the client click save button. From what i know, we have to keep context as short as possible.

This isn't an issue - the controller is instantiated per request. It doesn't persist while the user views the page. It sounds like you're misunderstanding at what point the controller is instantiated. When you instantiate the UnitOfWork within the controller's constructor, the process flow goes like this:

  • The user issues a POST request (by clicking 'Save').
  • The request reaches the server and the controller is instantiated (thereby instantiating the unit of work).
  • The action method is called.
  • The unit of work is disposed.

Where should i put business logic? Do i put it in repository? So i would call UoW.departmentRepository.Validate(department) before save. But then, what if i need to validate entity which relate to other entity. Do i call UoW.departmentRepository.Validate(course, department)?

Typically, your business logic would be abstracted into a separate layer that sits between your web application and your repositories. Tutorials that show you repositories injected directly into controllers assume that you have "thin" business logic.

However, validation definitely isn't the job of a repository. You should create a separate view model for each view and validate those in your controller. The repository should be used pretty much solely for CRUD operations.

like image 151
Ant P Avatar answered Sep 30 '22 13:09

Ant P