Recently at my job, we’ve decided to make a new project base for our company. We currently have an MVC 3 base, but considering MVC 5 is the new norm, it is time we get caught up with the latest and “greatest” (greatest used loosely). We decided that we were going to change our strategy with communicating with the database. Currently we use an ORM provided by Microsoft called Entity Framework. Entity Framework is a great ORM, however, when dealing with multi-million(s) set of records we’ve found it to be sub-par. I leave that for another topic at a later date.
The goal of this semi tutorial is to outline a project setup that has a model, service, and data layer, with the model and service layer being reusable from a MVC site to an Android and iOS app. However, with this project setup you could easily implement a WPF application, Silverlight, or even console apps. Resulting in a true “N-tier” architecture.
Below are some of the technologies that are going to be talked about and I’m going to assume some knowledge on them:
1.) AutoFac
2.) FluentValidation
3.) SqLite.NET
4.) Xamarin
5.) NHibernate
Project Setup
First thing we need to do is create a new solution and add two Solution Folders. Create one for “Web” and one for “Mobile”, we separate these just for our convenience. Then we need to start adding projects to the new solution. Using Visual Studio 2015 you should have everything you need built in to your templates if not you may need to download Xamarin from here and of course make sure you have NuGet installed in Visual Studio. Next you’re going to add four Portable Class Libraries and suffix them with “*.Configuration”, “*.Models”, “*.Services”, “*.Validation”. It is imperative that these be a “Portable Class Library” in order to get this to work correctly. Below are the options you will want to set for all four PCLs.
Next we need to add our actual end-point projects. So under the “Web” solution folder we created earlier, we need to add a new MVC project. You can configure the site with what ever settings you’d like, but be sure to have the API enabled. Then we’re going to add a Xamarin.Forms application to the “Mobile” solution folder. When you add a “Xamarin.Forms” project to your solution, it will automatically add a “*.Droid”, “*.iOS” and “*Mobile” projects. Since a Xamarin.Forms application requires a Business License to run you may need to upgrade your licensing. Anyway, with all that setup completed you should have a Solution Explorer look like this:
Now we have an ideal project setup. In a “perfect” scenario we can use the same models and services for both our web application and mobile applications. But what about a data layer? How’s my services going to talk to my database on the phone vs the web, there can’t possibly be a solution??
On the contrary, there is! The infamous IRepository Pattern! If you haven’t heard of it don’t sweat it! The idea behind the “IRepository” pattern, is essentially your service layer doesn’t care or know about the repository. This seems like a pretty simple ideology, but it comes with some caveats too. But for example we have the following IRepository:
IRepository Setup
public interface IRepository
{
IEnumerable GetAll() where T : class, new();
IEnumerable GetAll(Func<T, bool> expression) where T : class, new();
void InsertOrUpdate(T source) where T : class, new();
void Delete(T item) where T : class, IRemovable, new();
void Purge(T item) where T : class, new();
}
Here we make the definitions and the contract for any Repository that implements IRepository. We have the basic operations you do with a database, a SELECT as a “GetAll”, an insert/update routine, a delete, and a purge operations. The only difference between “Delete” and “Purge” in this case, is that the Delete method requires the parameter to be an IRemovable which only has a property of “IsActive”. This is used to just set the flag to ‘false’.
So how do our services interact with the IRepository? Lets take a look at a code snippet below:
public abstract class BaseService where T : class, new()
{
private IRepository Repository;
public BaseService(IRepository repo)
{
Repository = repo;
}
public virtual IEnumerable GetAll()
{
return Repository.GetAll();
}
public virtual IEnumerable GetAll(Func<T, bool> expression)
{
return Repository.GetAll(expression);
}
protected void InsertOrUpdate(T source) where T : class, new()
{
Repository.InsertOrUpdate(source);
}
protected void Purge(T source)
{
Repository.Purge(source);
}
}
This is our BaseService, any other service we create will extend from this class. It provides all the base functionality with calling the IRepository API calls. So if we create a “User” service that is responsible for getting all the users in the database and the CRUD operations we would do the following:
public class UserService : BaseService
{
public UserProfileService(IRepository repository) : base(repository) { }
public IEnumerable GetProfiles(Func<User, bool> where = null)
{
return where == null ? GetAll() : GetAll(where);
}
public void SaveUser(User user)
{
InsertOrUpdate(user);
}
public void DeleteUser(User user)
{
Purge(user);
}
}
This is a pretty simple implementation, with no business rules put in place, but this is how you would be interacting with the IRepository.
Repository Association
Now, we all know that you can not instantiate an interface, so there has to be some concrete class somewhere that actually talks to the database. In fact in our case there will two or three different implementations. One for our MVC site, and one for each of our Mobile apps (we may be able to use one for mobile).
Within the .NET web world there are many ORMs we can choose from: NHibernate, EntityFramework, Linq2Sql, Signum Framework, etc. The list could go on and on. Lets use the commonly known Entity Framework! It’ll be a real simple representation; the caveat you have to remember when implementing this type of pattern is that you loose the “niceties” that come with a particular ORM and maybe some of the headache xD. Lets dive into it…
public sealed class EntityFrameworkReposity<T> : IRepository
{
public IEnumerable<T> GetAll() where T : class, new()
{
using(var context = new DbContext())
{
return context.Table<T>();
}
}
... Implement the rest of the methods
}
After we’ve implemented the EntityFramework repository in a separate project we need to register the “EntityFrameworkRepository” implementation using a Dependency Resolver.
..
var container = new ContainerBuilder();
container.RegisterType<IRepository<T>>()
.As<EntityFrameworkRepository<T>>();
..
This is the “magic” behind making the services working. At runtime, when we need an instance of an IRepository<T>, our IoC will give an instance of EntityFrameworkRepository. Now this does required a bit of Autofac knowledge and this is how you register the interface specifically with Autofac. Next we’re going to move into how to share validation rules between platforms