1

As an answer to my own question:

What would be the most elegant way to use Entity Framework with Generic Repository, in Service Stack, and to write Integration \ Unit Tests for service?

At the moment, this is how my structure looks like:

Generic repository layer:

public class GenericRepository<TEntity> where TEntity : class
{
    internal DbContext Context;

    //...

    //CRUD Operations, etc.
}

Unit of work layer:

public class UnitOfWork : IDisposable
{   
    private readonly DbContext _context;

    public UnitOfWork(DbContext ctx)
    {
        _context = ctx;
    }

    private bool _disposed;

    private GenericRepository<User> _userRepository;

    public GenericRepository<User> UserRepository
    {
        get { return _userRepository ?? (_userRepository = new GenericRepository<User>(_context)); }
    }

    //...
}

Business layer:

public class UserBusiness
{

    public UnitOfWork UoW { get; set; }

    public void AddUser(Models.User user)
    {
        //Map from domain model to entity model
        var u = Mapper.Map<Models.User, DAL.Repository.User>(user);

        UoW.UserRepository.Insert(u);
        UoW.Save();
    }
}

API project:

public class AppHost : AppHostBase
{
    public AppHost() : base("Users Service", typeof(UsersService).Assembly) { }

    //...

    public override void Configure(Funq.Container container)
    {
        //...other configuration

        //UoW registration
        container.Register(c => new UnitOfWork(new DbContext("my-DB-connection"))).ReusedWithin(Funq.ReuseScope.Hierarchy);

        //Business layer class registration
        container.Register<UserBusiness>(c=>new UserBusiness {
            UoW = c.Resolve<UnitOfWork>()
        }).ReuseWithin(Funq.ReuseScope.Hierarchy);
    }
}

public class UsersService : Service
{
    public UserBusiness UB { get; set; }
    public object Post(User u)
    {
        UB.AddUser(u);
        //...               
    }
}

So when it comes to integration testing, I can just do something like this:

Declare _appHost

private ServiceStackHost _appHost;

And configure funq container like this:

public override void Configure(Funq.Container container)
{
    //...create mocked context
    var mockedContext = new Mock<IDbContext>();
    mockedContext.Setup(x => x.Set<User>()).Returns(new List<User>
    {
        new User { ID = 1, FirstName = "John", LastName = "Doe" }
    });
    //(or use effort or any other way to create it)

    container.Register(c => new UnitOfWork(mockedContext)).ReusedWithin(Funq.ReuseScope.Hierarchy);
}

And test as usual:

[Test]
public void Get_User_By_Id()
{
    //...generate client instance (JsonServiceClient) etc.

    var customer = client.Get(new GetCustomer { Id = 1 });    
    Assert.AreEqual("John", customer.FirstName);
    ///...
}

In addition to have all layers available for DI, and mocking, I also created IDbContext, IGenericRepository, IUnitOfWork, etc. interfaces. I didn't include it here in order to keep this as simple as I could.

But I would like to hear if there's a better (more elegant way) to do it.

ShP
  • 1,143
  • 1
  • 12
  • 41
  • You should define your Mappings in App start up not, in the user class. You're going to create a Mapping every time that code is called, instead of only once when the app starts – CSharper Jul 31 '15 at 16:21
  • @CSharper Yeah I know, I just put it there to show that there's some kind of mapping, off-topic anyway. :) – ShP Jul 31 '15 at 22:46

0 Answers0