ASP.NET, ASP.NET MVC5, Entity Framework, Identity, Web API

ASP.NET MVC5 Entity Framework / Repository Pattern and Unit of Work revisited

֍ Looking for ASP.NET Core ? follow this link

The code for this solution in this link

I’ll put Android development aside for a moment to write an update of an old entry related to ASP.NET and MVC.

Normally when the time goes by not only technology changes; New framework versions are released and us (developers) learn new tricks on how to use them. ASP.NET MVC is no exception.

I want to do the same exercise I did before but this time with a few tweaks and some additions (Unit of Work). I’ll show you how to build a very basic architecture for a fully functional ASP.NET MVC5 / WEB API application. Nowadays this can be called a full stack development. This application will be based on an N-Layered architecture:

Domain: class library referencing Entity Framework. Here you will have your domain classes (we will use Code First). The DbContext will live in this project.

Data Access: class library referencing Entity Framework and the Domain project. Repositories to access your domain objects. These will use a Base class and you will be able to write your own LINQ predicates or queries here (when needed). The Unit of Work class will also be located here.

note: The unit of work pattern will be used to centralize all your database calls to a unique instance of DbContext. This will save you a lot of problems in the future.

Business Logic: class library referencing Data Access and Domain. Here you will have services that interact to your repositories. Services can be grouped in managers. You will be putting most of your logic here.

Presentation Layer: an MVC5 project referencing the other projects plus EF and EF for SQL server. You should not have ANY business logic on this level of the architecture. The reason to do this kind of detachment is simple: let’s imagine you want to start using ASP.NET core, or maybe a WPF client. If your logic is on the BL layer all you have to do is write your views and call your managers to do any operation desired.

Let’s start by creating these projects on Visual Studio. You should have something similar to this:

project_structure.png

Domain

requires: Entity Framework

This is where your domain objects exist. These POCO structures are supposed to represent your logical business entities. We will create a base class that will have the unique identifier (key):


 public abstract class BaseEntity
 {
 [Key]
 public Guid Id { get; set; }
 }

An example concrete class will look like:


 public class Product : BaseEntity
 {
 public string Name { get; set; }
 public float Price { get; set; }
 public virtual Category Category { get; set; }
 }

You need the context which is basically the representation of the database:\


public class MyContext : DbContext
{
public static DbContext Create()
{
return new MyContext();
}

public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
}

note: I’m keeping this sample as  simple as I can. I’m not adding cascading rules for now.

Data Access

requires EntityFramework and a reference to Domain

This layer will be handling your queries. It’s important  to write your complex predicates here to have an optimized code. Avoid writing LINQ on top layers where you don’t have access to the raw context. If you do a WHERE from a GetAll() in the BL you already made a mistake by querying  a subset from “select all”. Your specific predicates should stay on each repository.

Unit of Work

The unit of work will serve as a common object among all your repositories. There should never be two instances of this object while a single scope is being executed (for example a web request). It’s a very simple yet useful pattern. You can define your object like:


public class UnitOfWork : IDisposable
 {
 public DbContext Context { get; set; }

 public UnitOfWork()
 {
 Context = MyContext.Create();
 }

public void Dispose()
 {
 if (Context != null)
 {
 Context.Dispose();
 Context = null;
 }
 GC.SuppressFinalize(this);
 }
 }

Repositories

Repositories are the objects responsable to interact (get, update, etc.) with your domain objects. They will do this using the Context you created on the Domain Layer. It’s VERY important to remember to use always the same instance of Context (via Unit of Work). There will be times were you can have more than once instance of a repository on the business logic and trying to modify an object through different contexts will cause lots of troubles (and exceptions).

We will create a Base Generic Repository. This will come handy to avoid writing common methods again. Pay special attention to the Context property and to the constructor that receives the Unit of Work.


public abstract class BaseRepository<TEntity> : IDisposable where TEntity : BaseEntity
{
public UnitOfWork UnitOfWork { get; set; }

protected DbContext Context
{
get
{
return UnitOfWork.Context;
}
}

public BaseRepository(UnitOfWork unitOfWork)
{
this.UnitOfWork = unitOfWork;
}

public void Dispose()
{
if (UnitOfWork != null)
UnitOfWork.Dispose();

GC.SuppressFinalize(this);
}

public virtual void SaveChanges()
{
Context.SaveChanges();
}

public virtual IQueryable<TEntity> GetQuery()
{
return Context.Set<TEntity>();
}

public virtual IEnumerable<TEntity> GetAll()
{
return Context.Set<TEntity>().ToList();
}

public virtual IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return GetQuery().Where(predicate).ToList();
}

public virtual int Count()
{
return GetQuery().Count();
}

public virtual bool Any(Expression<Func<TEntity, bool>> predicate)
{
return GetQuery().Any(predicate);
}

public virtual TEntity GetById(Guid id)
{
return Context.Set<TEntity>().FirstOrDefault(entity => entity.Id == id);
}

public virtual void Add(TEntity entity)
{
Context.Set<TEntity>().Add(entity);
}

public virtual void Delete(TEntity entity)
{
Context.Set<TEntity>().Remove(entity);
}
}

A concrete repository will look like:


public class ProductRepository : BaseRepository<Product>
{
public ProductRepository(UnitOfWork unitOfWork) : base(unitOfWork)
{
}

public Product GetByName(string name)
{
MyContext context = Context as MyContext;
return context.Products.FirstOrDefault(n => n.Name.Equals(name));
}
}

I hope you are starting to wrap your head about how this goes.

Business Logic

requires references to Data Access and Domain

Here is where you will write your algorithms and… well.. business logic. You can do that by using a combination of services and managers. You can define a Service as a middle layer between a manager and the repository. Managers are the objects that will be responsible for having the real logic. A manager can have one or more services to access to the required data.

Again, we will have a Base Generic Service and then each implementation. I will not include the code here since it’s very similar to the Base Repository (and you can browse it from the github repository). What its important is to remember the Unit of Work is passed through the constructor just like before.

A manager will look more or less like this:


public class StorageManager
 {
 public CategoryService CategoryService { get; set; }
 public ProductService ProductService { get; set; }

public StorageManager(UnitOfWork unitOfWork)
 {
 CategoryService = new CategoryService(unitOfWork);
 ProductService = new ProductService(unitOfWork);
 }

public void AddCategory(Category category)
 {
 CategoryService.Add(category);
 CategoryService.SaveChanges();
 }

public void AddProductToCategory(Product product, Guid categoryId)
 {
 var category = CategoryService.GetById(categoryId);
 product.Category = category;
 ProductService.Add(product);
 ProductService.SaveChanges();
 }
 }

Presentation Layer, the MVC5 / WEB API project

requires EntityFramwork, EntitiFramework SQL, references to all projects.

We are almost done ! all wee need to do know is incredibly easy: just start calling those managers on the Business Logic and get, update, delete our domain objects. The trick on this layer is to be responsable of creating a unique Unit of Work object. This object will (must) be unique and will live through each request. This can be easily achieved by creating a Base Controller class:


public abstract class BaseController : Controller
{
public UnitOfWork UnitOfWork { get; set; }

public BaseController()
{
UnitOfWork = new UnitOfWork();
}
}

And here is how to use it:


public class ProductController : BaseController
 {
 // GET: Product
 public ActionResult Index()
 {

StorageManager manager = new StorageManager(UnitOfWork);
 Category category = new Category()
 {
 Id = Guid.NewGuid(),
 Name = "Hello Category"
 };
 manager.AddCategory(category);

return View();
 }
 }

You can now see how easy is to detach your logic from your controllers. This will help you keep your code readable and easy to maintain. Not to mention the benefits of this kind of approach when working with collaborators. The same can be done for a Base Web Api Controller.

Final chapter: Entity Framework Migrations and The Identity Model

I’m assuming you are familiar with the code first approach and I wanted to keep the first section of the blog clean. Just in case, remember you can create your database by using your Package Manager Console:

1.png

Once you have enabled the migrations on the correct project (Domain in this case) you can create an initial migration and later calling update-database:

4.png

Just remember to have a correct database connection on your web.config


<!-- context (domain) connection -->
<add name="MyContext" connectionString="Data Source=(local);Initial Catalog=aspnetexample;Integrated Security=True; MultipleActiveResultSets=true" providerName="System.Data.SqlClient" />

ASP.NET Identity Model

I know what you are thinking: dude ! what the heck ! you forgot the User class on your domain ! I can tell you I didn’t. I just didn’t want to over complicate this tutorial at the beginning of it.

When you create an ASP.NET MVC5 project, you will notice a Models folder and inside of it the IdentiyModel.cs file. This file is responsable for the context related to the application’s Identity User (and it’s properties) and how this interacts with Roles.

I have seen people creating a unique context for both your Domain objects and for the Identity model. I think this is not a very good approach:

  • this will force you to have a library dependent Domain layer (will depend on the ASP.NET identity libraries).
  • will force you to inherit to classes with other keys
  • most important: you will be mixing presentation layer specific objects with domain objects. The IdentityUser is a presentation layer object. It has NOTHING to do with your domain.

You can have a User class in your Domain. In fact, it would be strange if you don’t. What I recommend you to do is to have both contexts (databases). One is related to your domain and the other to sessions and identity. The way to relate the IdentityUser with your domain User is through some property mapping. I will write about this soon. For now you can browse the sample from github.

Remember to run your migration and database related commands for the presentation layer as well !

Advertisements

4 thoughts on “ASP.NET MVC5 Entity Framework / Repository Pattern and Unit of Work revisited”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s