Need assistance in putting SOLID ideas into practise?

asp.net-mvc dapper entity-framework n-tier-architecture oop

Question

Juile Lerman's pluralsight course on "EF in Enterprise" really inspired me, therefore I made the decision to create my demo app.

I'm running the most recent versions of EF, SQL Server, and MVC on VS 2012 as well. I'm developing a sample application that follows SOLID guidelines. I'm doing this to learn more about how to use unit testing and DI.

In creating this sample application, I used the DB first strategy. UserDetails is the sole table it has, and this is how it appears in SQL Server. This table will be used for CRUD operations.enter image description here

I've layered my application as follows:

WESModel Resolution 1 My Model1.edmx file and the context class shown below are both included in this layer.

namespace WESModel
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using WESDomain;

    public partial class WESMVCEntities : DbContext
    {
        public WESMVCEntities()
            : base("name=WESMVCEntities")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }

        public DbSet<UserDetail> UserDetails { get; set; }
    }
}

WESDomain Resolution 2. My domain classes are included in this layer (or POCO classes). In my WESModel layer, these POCO classes were really produced automatically. I shifted them to this layer outside. The single POCO class looks like this.

namespace WESDomain
{
    using System;
    using System.Collections.Generic;

    public partial class UserDetail:IUserDetail
    {
        public int Id { get; set; }
        public string UserName { get; set; }
    }
}

3. WESDataLayer Alternative: This layer has references to the two levels above's DLLs. As shown below, this layer contains my Repository class. I'm keeping the IRepository in the same class for the time being.

namespace WESDataLayer
{ 
    public class UserDetailRepository : IUserDetailRepository
    {
        WESMVCEntities context = new WESMVCEntities();

        public IQueryable<IUserDetail> All
        {
            get { return context.UserDetails; }
        }

        public IQueryable<IUserDetail> AllIncluding(params Expression<Func<IUserDetail, object>>[] includeProperties)
        {
            IQueryable<IUserDetail> query = context.UserDetails;
            foreach (var includeProperty in includeProperties) {
                query = query.Include(includeProperty);
            }
            return query;
        }

        public IUserDetail Find(int id)
        {
            return context.UserDetails.Find(id);
        }

        public void InsertOrUpdate(UserDetail userdetail)
        {
            if (userdetail.Id == default(int)) {
                // New entity
                context.UserDetails.Add(userdetail);
            } else {
                // Existing entity
                context.Entry(userdetail).State = EntityState.Modified;
            }
        }

        public void Delete(int id)
        {
            var userdetail = context.UserDetails.Find(id);
            context.UserDetails.Remove(userdetail);
        }

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

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

    public interface IUserDetailRepository : IDisposable
    {
        IQueryable<IUserDetail> All { get; }
        IQueryable<IUserDetail> AllIncluding(params Expression<Func<UserDetail, object>>[] includeProperties);
        UserDetail Find(int id);
        void InsertOrUpdate(UserDetail userdetail);
        void Delete(int id);
        void Save();
    }
}

Solution for ConsoleApplication 4: My UI layer is this. In my finished project, it will be my MVC application. Here, I just do a database query and show the results. The code appears like this.

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
             IUserDetailRepository repo = new UserDetailRepository();

             var count = repo.All.ToList().Count().ToString();
             Console.WriteLine("Count: {0}", count);
             Console.ReadLine();

        }
    }
}

Question: There is no reference to the EF DLL in my UI layer. It does, however, include a Repository class instance. In MVC application, my controller will have an instance of repository class or UnitOfWork.

Is this the proper course of action?

B) Can I abstract it in any way?

c) What if I wish to replace EF with Dapper or another ORM tool in the future?

How can I use my DI tool in this project, question d? Which layer should it be in?

Unit testing (e). I am aware of StructureMap and want to utilize it in my project in a manner that will allow me to replace it with Ninject in the future. How can I do this?

I appreciate you taking the time to read my lengthy query, and if you could please send me in the appropriate route.

1
4
7/27/2013 4:40:25 PM

Accepted Answer

Question: My UI layer does not have any ref to EF DLL. However, It has an instance of Repository class. In MVC application, my controller will have an instance of repository class or UnitOfWork.

Yes, there must be no EF references in UI layer classes. However, they cannot make a reference to the physical repository in order to achieve this. If a Service Layer is not used in an MVC application, the Controller will only have a reference to the IUserDetailRepository and will have to wait for a concrete type to be constructed. Depending on how you implement it, UnitOfWork:-)

a) Is this the right thing to do ?

It seems like your design is going in this direction, which is what is referred to as "loose coupling."

b) Is there any way i can abstract it ?

You may use a Dependency Resolver, of course. You won't need to refer to concrete types since your code will solely be built on abstractions in this manner.

c) What if in future i want to swap out EF with Dapper or any other ORM tool ?

You need to have a Data Access Layer, for instance, a library with your actual IXxxRepository contract implementations. It will be EF implementations in your instance. You will need to re-implement this layer after you switch to Dapper. There is a reasonable limit on the refactoring.

d) How do i fit my DI tool in this project ? In which layer it should be ?

The UI layer will be the ideal location for your DI tool. When the program launches, you will specify the dependencies and bindings, and everything will function flawlessly.

e) Unit testing. I am aware of StructureMap and want to make use of it in this project in such a way that in future i should be able to swap it out with Ninject. How do i achieve this ?

To plug in another, do you need to disconnect your Dependency Resolver first? No issue, simply plan ahead when setting up your DR setup to have the least amount of connection with your application. In certain circumstances, there are some recommendations to reduce coupling. We have an MVC application as well as service, business, data access, and infrastructure layers on the project I'm working on right now. Only the infrastructure and Web UI layers have a reference to Ninject, which we utilize as DR. It's quite simple to disconnect, and we've previously tested Unity in this manner.

One additional thing: UserDetail shouldn't be covered by a contract. Use Dependency Injection on stateless classes rather than on all classes like DTOs since there is no need for it.

3
7/28/2013 5:16:51 PM

Popular Answer

Eliminate the if statement if you use implicit variable type rather than explicit variable typing (i.e.var keyword), you can identify dependencies much more quickly. Choose to utilize an interface wherever feasible (IUserDetailRepository over the application of a class (UserDetailRepository ).

examples:

1) permit type determination by compiler

var repo = new UserDetailRepository();

Type is established via class reference in 2.

UserDetailRepository repo = new UserDetailRepository();

Type 3 is established by the interface

IUserDetailRepository repo = new UserDetailRepository();

You may swap in other references that adhere to the same interface by enabling Interface to select the type rather than the compiler (i.e.IUserDetailRepository repo = new DapperUserDetailRepository();

Inversion of Control (IoC), which is the technique of utilizing a particular IoC container (Ninject, CastleWinsor, Unity, etc.) to automatically resolve your dependencies, is another concept that you are approaching.new keyword in full.

Given that you brought up StructureMap, here is an illustration of how it functions:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            IContainer container = ConfigureDependencies();
            IUserDetailRepository repo = container.GetInstance<IUserDetailRepository>();

            var count = repo.All.ToList().Count().ToString();
            Console.WriteLine("Count: {0}", count);
            Console.ReadLine();

        }

        private static IContainer ConfigureDependencies() {
            return new Container(x =>{
                x.For<IUserDetailRepository>().Use<UserDetailRepository>();
            });
        }
    }
}


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow