2

In my project I had a controller dependency on IRepositoryProvider among others.

public class HomeController : BaseController
{
    public HomeController(ISessionWrapper sessionWrapper,
                          IRepositoryProvider repositoryProvider,
                          IApplicationConfiguration applicationConfiguration)
        : base(sessionWrapper, repositoryProvider, applicationConfiguration)
    {}

    ...

}

IRepositoryProvider and its implementation live in a BLL layer. Another thing to note is that IRepositoryProvider has some parameters also. These are used to determine which connection strings to use (Environment*5 possible connections).

    public RepositoryProvider(string environment, IApplicationConfiguration applicationConfiguration)
    {
        _applicationConfiguration = applicationConfiguration;
        _environment = environment;
    }

This all works fine with two layers and this Ninject config.

kernel.Bind<IRepositoryProvider>()
      .To<RepositoryProvider>()
      .InRequestScope()
      .WithConstructorArgument("environment",    
                                context => context.Kernel.Get<ISessionWrapper>().CurrentEnvironment)
      .WithConstructorArgument("applicationConfiguration",
                                context => context.Kernel.Get<IApplicationConfiguration>());

My issue develops when I introduced a service layer. Instead of relying on IRepositoryProvider in my controllers for data access, I want to use the service layer. Ideally then I don't want to reference the BLL layer, and only the Service layer.

public class HomeService : IHomeService
{
    public IRepositoryProvider RepositoryProvider { get; private set; }

    public HomeService(IRepositoryProvider repositoryProvider)
    {
        RepositoryProvider = repositoryProvider;
    }
    ...
}

So my question is this: Is it possible for me to not reference both the Service and BLL layers from the MVC project? Or is this whole setup a massive code smell?

Thanks.

UPDATE: I suppose I should have said my ideal references. Web -> Service -> BLL. At the moment Web references both Service and BLL in order for Ninject to resolve everything.

UPDATE 2: Does this seem like a possible solution? How to tell Ninject to bind to an implementation it doesn't have a reference to

Community
  • 1
  • 1
merekel
  • 443
  • 5
  • 15
  • You would still use the IRepositoryProvider defined in the BLL, wouldn't you? So I guess you would still need to reference it. But I don't see what Ninject has to do with it – treze Apr 19 '13 at 18:04

2 Answers2

3

This is how I usually architect my MVC projects depending on requirements.

Presentation Layer > Service Layer > Business Layer > Data Access Layer.

Presentation Layer contains : ViewModels, Views, Controllers. (References the Service Layer, Ninject ddl)

Service Layer : WCF. (References the BAL, etc)

Business Layer : Contains what I call Orchestrators and their interfaces (References DAL, Domain)

Data Access Layer: Contains the Repositories and their Interfaces (References Domain)

Domain: Contains the POCO objects

Core : Where I actually install and configure Ninject (References the BAL, DAL, etc)

To Add Ninject to a another Project other than the Presentation Layer:

Add the following to Global.Asasx.cs:

DependencyResolver.SetResolver(new NinjectDependencyResolver());

Then create a new project sucche as core. Install Ninject there and add the following class:

You will need to reference the Ninject dll from the Presentation Layer

 public class NinjectDependencyResolver : IDependencyResolver {
    private IKernel kernel;

    public NinjectDependencyResolver() 
    {
        kernel = new StandardKernel();
        AddBindings();
    }

    public object GetService(Type serviceType) 
    {
        return kernel.TryGet(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType) 
    {
        return kernel.GetAll(serviceType);
    }

    public IBindingToSyntax<T> Bind<T>() 
    {
        return kernel.Bind<T>();
    }

    public IKernel Kernel 
    {
        get { return kernel; }
    }

    private void AddBindings() 
    {
        //Add your Bindings here
    }

}
Flavia
  • 563
  • 4
  • 9
  • The implementation of ISessionWrapper is used in various locations in some controllers. IApplicationConfiguration I supposed could be removed since it is only used in 1 or 2 times for controllers, I don't see how either of these has to do with what I asked yet. – merekel Apr 19 '13 at 18:16
  • So it is used in both the controller(s) and repository(ies)? – Flavia Apr 19 '13 at 18:18
  • Which ones? ISessionWrapper is only used in the Web layer, but it contains the current selected environment which is needed to know which connections to use. IApplicationConfiguration is used to retrieve the correct connection strings as well as some other web.config settings (such as allowed AD groups, available environments, etc). – merekel Apr 19 '13 at 18:29
  • I'm confused with your constraints. Let me edit my reponse and show you how I architect my MVC projects. That may help you. – Flavia Apr 19 '13 at 18:44
  • So you have removed the Ninject configuration (like von d. below) from the MVC project and placed it separately? Example of this? – merekel Apr 19 '13 at 19:00
  • 1
    Just read von d.'s response. Yes! I install and configure ninject in a different project. And only have a reference from the Presentation layer to the ninject ddl. I don't have a sample project here with me, but I can put it on github later today if you can wait. – Flavia Apr 19 '13 at 19:04
  • I ended up using Ninject Modules in a DependencyResolver layer. The MVC specific version of Ninject then loads these modules. A downside is that you lose the InRequestScope() level of scoping on bindings though. – merekel Apr 22 '13 at 19:24
  • 1
    I put a sample project on github. Look for flaviacarioca\Registration – Flavia Apr 22 '13 at 23:57
2

IRepositoryProvider and its implementation live in a BLL layer... Is it possible for me to not reference both the Service and BLL layers from the MVC project

With those two statement of yours the answer is NO, it is not possible for you "not" to reference those layers. The best approach of minimizing references is to separate your interfaces from the implementations. You can have for example the following:

The Domain Layer, contains your POCO and interface

  • Product (a sample class)
  • IRepository (an interface)

The Service Layer, contains the implementaion of your interfaces

  • Have a reference to the Domain layer
  • Implements IRepository (e.g. ProductRepository : IRepository)

Dependency Injection Layer

  • Is aware of both the Domain and Service layers

The MVC Project

  • Have a reference to the Domain layer to know about the POCOs and repository signatures
  • Have a reference to the DI layer but doesn't know how it exactly works. So you can swap out DI framework later and everything will still work.

You can expand that layer as you see fit. You can insert the BLL layer in between the Domain and Service layer and you don't need reference it anywhere.

von v.
  • 16,868
  • 4
  • 60
  • 84
  • Did you mean MVC only references the Service layer instead of the Domain? From what I see Ninject still needs to know both types (interface and concrete). I made an edit on my question about the use of modules and Ninject also. – merekel Apr 19 '13 at 18:32
  • Inject needs to know both that is correct and it is because it's Ninject's job to know it. It will do the object creation and not the MVC project. So Ninject needs to know everything and MVC just needs to know about the Domain (and the signatures/intefaces). – von v. Apr 19 '13 at 18:35
  • My point was that if Ninject needs to know both, then both layers would need to be referenced. – merekel Apr 19 '13 at 18:40
  • Ah I think I know where the confusion lies. You did not mention where you are doing the Ninject configuration. I think you have it in MVC and that is why you think that both project still needs to be referenced in MVC. If yes then you have not separated your project clearly. You need to abstract the "injection configuration" - have a separate project for it. The advantage of that is that each assembly has its own responsibility that doesn't spill out to other assemblies. – von v. Apr 19 '13 at 18:46
  • Yep I am using the Ninject.MVC project. Do you have a name or example for the separate Ninject project? Does this have to do with the link I added to my question about modules? – merekel Apr 19 '13 at 18:52
  • I should also add (though it probably doesn't make much difference) that I don't have table based repositories, but database based repositories. This website is an interface for various parts of a large health related website and system. – merekel Apr 19 '13 at 18:57