0

I have an ASP.NET MVC application that has my controller calling a command invoker to execute CRUD operations. The command handlers are in my Domain Layer assembly. One of the command handlers saves a record using the following code:

public class SaveTransactionCommandHandler : ICommandHandler<SaveTransactionCommand>
{
    public void Handle(SaveTransactionCommand command)
    {
        using (GiftCardEntities db = new GiftCardEntities())
        {
            db.Transactions.AddObject(new Transaction
            {
                GiftCardId = command.GiftCardId, 
                TransactionTypeId = Convert.ToInt32(command.TransactionTypeId), 
                Amount = command.Amount,
                TransactionDate = DateTime.Now
            });
            db.SaveChanges();
        }
    }
}

However, as you can see, my handler depends on an ObjectContext (EF). I'm in the process of learning Dependency Injection with Ninject. Now I know that my handler (domain object) should not be dependent on any data layer objects. But in my case the handler is dependent on GiftCardEntities which is an ObjectContext. How do I change my handler so that it is decoupled from the ObjectContext?

Ray
  • 4,679
  • 10
  • 46
  • 92

1 Answers1

3

You should use Repository pattern. Repositories will abstract the actual data access technology used. This way you can have multiple repository implementations for different data access technologies that you can switch without changing your business layer code. So, your handler will look like

public class SaveTransactionCommandHandler : ICommandHandler<SaveTransactionCommand>
{
    readonly ITransactionRepository repository;

    public SaveTransactionCommandHandler(ITransactionRepository repository)
    {
          this.repository = repository;
    }
    public void Handle(SaveTransactionCommand command)
    {

            repository.Save(new Transaction
            {
                GiftCardId = command.GiftCardId, 
                TransactionTypeId = Convert.ToInt32(command.TransactionTypeId), 
                Amount = command.Amount,
                TransactionDate = DateTime.Now
            });

    }
}  

Repository instance will be injected to your handler by DI container, ninject in your case.

Vitaliy Tsvayer
  • 765
  • 4
  • 14
  • I agree that the content/repository should be injected and not instantiated. However, what do you gain from adding an extra repository abstraction layer? In case you never need it b/c there's not going to be multiple data access technologies "at once" you've only added complexity and cost for nothing. In case you will switch technologies, they'll either be similar and thus it'll be very easy to adapt even without an abstraction, or they'll not be similar and in this case the abstraction only gave you a false sense of security (and more work and complexity...) – BatteryBackupUnit Jul 20 '15 at 06:37
  • @tsvayer: I tried using the Repository pattern but now I find myself with the same problem but in my TransactionRepository class. How do I inject the ObjectContext in that class? – Ray Jul 20 '15 at 06:52
  • @BatteryBackupUnit, sure if you have only tens of Handlers and couple more places where you access DBContext directly there is no need for extra abstraction layer. Depending on the size of application at hand I would question the need for DI container also. You do not need container to use DI pattern. But at some point it is not that simple to switch underlying data access technology with hundreds message handlers in your project. Another advantage is that it is easier to mock IRepository interface for unit testing or implement fake in-memory repository. – Vitaliy Tsvayer Jul 20 '15 at 07:29
  • @Ray, please look at question below on how to integrate DBContext with ninject in combination with repository pattern: http://stackoverflow.com/questions/11921883/how-to-handle-dbcontext-when-using-ninject – Vitaliy Tsvayer Jul 20 '15 at 07:34
  • Thanks, got it to work now. I placed ITransactionRepository in my Domain layer, then I registered ITransactionRepository with Ninject and the TransactionRepository was placed in the Data Access layer which gives me direct access to ObjectContext so I don't need to inject it. – Ray Jul 20 '15 at 07:43
  • yes but all of this can be achieved by just abstracting the 'DbContext' without doing a ["full repository pattern"](http://martinfowler.com/eaaCatalog/repository.html). So instead of creating `ITransactionRepository` (and `IFooRepository` and `IBarRepository`,...) creating an `IRepository` would be entirely sufficient as far as abstraction goes. – BatteryBackupUnit Jul 20 '15 at 08:28
  • @BatteryBackupUnit, there is much more to say about actual repository implementation. Generic interface implementation is often enough and there are various examples available. Sometimes you would want to hide your specific LINQ behind repository also, that is when you would need more specialized repository interfaces. For example, IProductRepository.GetAllExpiredProducts. You could use C# extensions for that, but it would make it impossible to mock for unit testing. You could also use Criteria Pattern here, but direct LINQ is often enough. – Vitaliy Tsvayer Jul 20 '15 at 08:45