简体   繁体   中英

Standardize Repository, UnitOfWork, IOC Container Asp.Net MVC

After read some articles about DI, Repository Pattern,... I have created a project with Asp.Net MVC. Below are some classes. It worked, but I'm wondering what I did are standard? Is that correct pattern? If no, how can I adjust to make it better?

Thank you in advance.

IGenericRepository interface:

public interface IGenericRepository<TEntity>: IDisposable where TEntity : class
{

IEnumerable<TEntity> Get(
            Expression<Func<TEntity, bool>> filter = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
            string includeProperties = "");

bool Contains(Expression<Func<TEntity, bool>> predicate);

TEntity GetById(params object[] keys);

TEntity Find(Expression<Func<TEntity, bool>> predicate);

TEntity Insert(TEntity t);

void Delete(TEntity t);

int Delete(Expression<Func<TEntity, bool>> predicate);

int Update(TEntity t);

int Count { get; }

}

GenericRepository class: (I will implement the functions later)

public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity:class
{
    internal GMSDbContext db;
    internal DbSet<TEntity> dbSet;

    public GenericRepository(GMSDbContext dbContext)
    {
        db = dbContext;
        dbSet = db.Set<TEntity>();
    }

    public int Count
    {
        get
        {
            throw new NotImplementedException();
        }
    }

    public bool Contains(Expression<Func<TEntity, bool>> predicate)
    {
        throw new NotImplementedException();
    }

    public int Delete(Expression<Func<TEntity, bool>> predicate)
    {
        throw new NotImplementedException();
    }

    public void Delete(TEntity t)
    {
        throw new NotImplementedException();
    }

    public TEntity Find(Expression<Func<TEntity, bool>> predicate)
    {
        throw new NotImplementedException();
    }

    public IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
    {
        throw new NotImplementedException();
    }

    public TEntity GetById(params object[] keys)
    {
        throw new NotImplementedException();
    }

    public TEntity Insert(TEntity t)
    {
        throw new NotImplementedException();
    }

    public int Update(TEntity t)
    {
        throw new NotImplementedException();
    }


    #region IDisposable Support
    private bool disposedValue = false; // To detect redundant calls

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                db.Dispose();
            }

            disposedValue = true;
        }
    }

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

}

IAccountRepository interface:

public interface IAccountRepository : IGenericRepository<Account>
{
}

AccountRepository class:

public class AccountRepository: GenericRepository<Account>,IAccountRepository
{
    public AccountRepository(GMSDbContext db) : base(db) { }
}

IUnitOfWork interface:

public interface IUnitOfWork: IDisposable
{
    void SaveChanges();
    IAccountRepository AccountRepository { get; }
}

UnitOfWork class:

public class UnitOfWork : IUnitOfWork
{
    private GMSDbContext db;
    private IAccountRepository accountRepo;

    public UnitOfWork()
    {
        db = new GMSDbContext();
    }

    public IAccountRepository AccountRepository
    {
        get
        {
            if (accountRepo != null) return accountRepo;
            else return new AccountRepository(db);
        }
    }

    public void SaveChanges()
    {
        db.SaveChanges();
    }

    #region IDisposable Support
    private bool disposedValue = false; // To detect redundant calls

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                db.Dispose();
            }

            disposedValue = true;
        }
    }

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

IAccountService interface:

public interface IAccountService
{
    int CheckLogin(string username, string password);
    Account GetAccountByUsername(string username);
}

AccountService class:

public class AccountService : IAccountService, IDisposable
{
    private IUnitOfWork unitOfWork;
    public AccountService(IUnitOfWork unitOfWork)
    {
        this.unitOfWork = unitOfWork;
    }
    #region Serivce Methods
    public int CheckLogin(string username, string password)
    {
        var entity = unitOfWork.AccountRepository.
            Find(o => o.Username.Equals(username, StringComparison.OrdinalIgnoreCase) 
            && o.Password.Equals(password, StringComparison.OrdinalIgnoreCase));
        if (entity == null) return -1;
        else {
            if (entity.IsEnabled) return 0;
            else return -2;
        }

    }

    public Account GetAccountByUsername(string username)
    {
        throw new NotImplementedException();
    }
    #endregion


    #region IDisposable Support
    private bool disposedValue = false; // To detect redundant calls

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                unitOfWork.Dispose();
            }

            disposedValue = true;
        }
    }

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

AccountController class:

public class AccountController : Controller
{
    private IAccountService accountService;
    public AccountController(IAccountService accountService)
    {
        this.accountService = accountService;
    }
    // GET: Admin/Account
    public ActionResult Index()
    {
            return View();
    }
}

I use Simple Injector for IOC container:

public static class SimpleInjectorInitializer
{
    /// <summary>Initialize the container and register it as MVC3 Dependency Resolver.</summary>
    public static void Initialize()
    {
        var container = new Container();
        container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();

        InitializeContainer(container);

        container.RegisterMvcControllers(Assembly.GetExecutingAssembly());

        container.Verify();

        DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
    }

    private static void InitializeContainer(Container container)
    {

        // For instance:
        container.Register<IAccountService, AccountService>(Lifestyle.Scoped);
        container.Register<IUnitOfWork, UnitOfWork>(Lifestyle.Scoped);
    }
}

Repositories and UnitOfWork on top of EntityFramework context is not a good idea .

When you're using EntityFramework and you instantiate your DbContext – you're creating a new UnitOfWork.

There is no point in creating IGenericRepository<TEntity> and then implementing it for each entity. As you are just wrapping DbContext and create unneeded code. If you don't want to create/inject an instance of DbContext into your controller (eg for Unit testing). You may create an IGMSDbContext interface and its implementation like:

public interface IGMSDbContext 
{
    DbSet<Account> Accounts { get; set; }

    int SaveChanges();
}

public class GMSDbContext: DbContext, IGMSDbContext
{
    public DbSet<Account> Accounts { get; set; }

    public GMSDbContext(string connection) : base(connection)
    {
    }

    public GMSDbContext() : base("your connection string name")
    {
    }
}

Then just inject IGMSDbContext into your service:

private IGMSDbContext dbContext;

public AccountService(IGMSDbContext dbContext)
{
        this.dbContext = dbContext;
}

In this way you can use context in your code this.dbContext.Accounts.Where....

Above implementation has a number of benefits:

  1. You are not reinventing the wheel, as IGMSDbContext contains everything you need (LINQ, UnitOfWork).
  2. You don't need to implement and maintain code for IGenericRepository<T>
  3. You still can easily mock IGMSDbContext for unit test.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM