Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Ninject in a SOLID application architecture

I'm starting with MVC3 and want to use some flexible architecture, so I've read tens of blogs, a book (Pro ASP.NET MVC 3), read about SOLID principles and finally got to an application structure I like (or at least I think so, so far, because I haven't built anything on it yet):

enter image description here

In this structure:

  • Domain holds the POCO classes and defines the service interfaces
  • Services implements service interfaces and defines repositories interfaces
  • Data implements repositories interfaces
  • WebUI and Domain use Services
  • Services use Repositories
  • WebUI, Services and Data depend on Domain for POCO classes

The main reason for Domain using Services is to validate unique keys on the Validate methods of POCO (IValidatable) classes.

I'm starting to build a reference application with this structure but I have faced, so far, two problems:

  1. I'm using a Data.Tests project with unit tests for the repositories, but haven't found a way to inject (using Ninject) a implementation of the service (in the constructor or otherwise) on the model, so the Validate method can call the CheckUniqueKey on the service.

  2. I haven't found any reference about hooking up Ninject to a TEST project (lots of for the WebUI project).

What I'm trying to achive here is beeing able to switch from EF to something else like DAPPER, by just changing the DATA assembly.

UPDATE

Right now (as of 09-AUG-2011) Ninject is working but I think I'm missing something.

I have a CustomerRepository with two constructors:

public class CustomerRepository : BaseRepository<Customer>, ICustomerRepository
{
    // The repository usually receives a DbContext
    public CustomerRepository(RefAppContext context)
        : base(context)
    {
    }

    // If we don't receive a DbContext then we create the repository with a defaulte one
    public CustomerRepository()
        : base(RefApp.DbContext())
    {
    }

    ...
}

On the TestInitialize:

// These are for testing the Repository against a test database

[TestInitialize()]
public void TestInitialize()
{
    // Context used for tests
    this.context = new RefAppContext();

    // This is just to make sure Ninject is working, 
    // would have used: repository = new CustomerRepository(context);

    this.kernel = NinjectMVC3.CreateKernel();

    this.kernel.Rebind<ICustomerRepository>().To<CustomerRepository>().WithConstructorArgument("context", context);

    this.repository = kernel.Get<ICustomerRepository>();

}

On the Customer class:

public class Customer : IValidatableObject 
{
    ...

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        // I want to replace this with a "magic" call to ninject
        CustomerRepository rep = new CustomerRepository();

        Customer customer = rep.GetDupReferenceCustomer(this);

        if (customer != null)
            yield return new ValidationResult("Customer \"" + customer.Name + "\" has the same reference, can't duplicate", new [] { "Reference" });
    }

    ...
}

What would be the best way to use Ninject in this scenario?

Any help will be highly appreciated.

ANSWER, SORT OF

I'll consider this question as aswered so far. I could get Ninject working, sort of, but it looks like achiving the Dependency Inversion Principle (DIP) of SOLID is going to take some more time.

In that respect, I had to lump together Domain, Services and Data, I'll create another question some other time and keep the project going the usual way for now.

Thanks everybody.

like image 581
Miguel Veloso Avatar asked Aug 03 '11 00:08

Miguel Veloso


1 Answers

Unit testing should be done without Ninject. Just create an instance of the object under test and inject a mock for every dependency manually.

For Integration Tests you can use the kernel inclusive all bindings from the application bootstrapper and rebind everything you want to replace by a Mock. e.g. Replace the Session binding by one that uses an in memory data storage instead of a real database.

like image 118
Remo Gloor Avatar answered Nov 09 '22 01:11

Remo Gloor