4

I would like to use Castle Windsor for dependency injection for my solution consisting of the following projects:

  1. Mvc [ASP.NET MVC 3 Web Application]: presentation layer (depends on Business and Models)
  2. Business [Class Library]: business layer (depends on DataAccess and Models)
  3. DataAccess [Class Library]: data access layer (depends on Models)
  4. Models [Class Library]: model layer

In the business layer there is a class called PostService implementing IPostService that manages blog posts. The PostsController of the Mvc project depends on IPostService. However, PostService (the corresponding concrete implementation) itself depends on IPostRepository.

Where do I configure Castle Windsor to return an instance of PostRepository to resolve IPostRepository? The Mvc project doesn't know about the DataAccess project. Thus, I can't configure the component bindings in global.asax or somewhere else within Mvc.


[Update] Dependency Diagram

Now that I've found a solution (thanks again, Darin Dimitrov!) I'd like to share the current dependency diagram with you.

Project dependencies

Marius Schulz
  • 15,976
  • 12
  • 63
  • 97

4 Answers4

10

Create and place Windsor installer classes (IWindsorInstaller interface implementations) in your class libraries, for example:

public class PostRepositoryInstaller: IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        var allTypesFromBinDir = AllTypes
            .FromAssemblyInDirectory(new AssemblyFilter(HttpRuntime.BinDirectory));

        container.Register(allTypesFromBinDir
            .BasedOn<IPostRepository>()
            .WithService.FromInterface()
            .Configure(c => c.LifeStyle.Transient));
    }
}

Then in your Global.asax install your dependencies:

protected virtual void Application_Start()
{
    new WindsorContainer().Install(FromAssembly.InDirectory(new AssemblyFilter(HttpRuntime.BinDirectory)));
}
Kalman Speier
  • 1,937
  • 13
  • 18
2

Use installers. from the global.asax you can call:

_container.Install(FromAssembly.InDirectory(new AssemblyFilter(HttpRuntime.BinDirectory, "YourNamespaceToScan*.dll")));

In your business, DA and Model projects you can then add installers to install dependancies for each:

 public class ServicesInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
               ...);
        }
    }
1

You should configure the DI container in the MVC project. This is where everything comes into live. This where all the assemblies must be referenced including the data access layer of course (without referencing a concrete data access your MVC application simply cannot work). So the MVC application knows all about the other layers. Application_Start in Global.asax is a good place to configure a DI container.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • The MVC project does only know about *Model* and *Business*. The *DataAccess* project is referenced by the *Business* project so that it can we swapped without affecting the presentation layer. – Marius Schulz Jun 05 '11 at 17:50
  • 2
    The data access project implementing your DAOs should not be referenced by your business project. It's the MVC project that should know about all the other layers. So it's by modifying your DI container (which as I said should be configured in the MVC layer) that you could achieve this. Simply reference another assembly implementing your repositories (data access layer) into the MVC project and reconfigure the container to use it. – Darin Dimitrov Jun 05 '11 at 17:55
  • Thanks for your post — it seems I misunderstood the splitting of dependencies using dependency injection ... – Marius Schulz Jun 05 '11 at 17:58
  • One more thing ... What about `PostRepository` and `IPostRepository` — they are defined in *DataAccess* and thus unknown to *Business* without referencing *DataAccess*. Are they supposed to live within *Models*? – Marius Schulz Jun 05 '11 at 18:02
  • @Marius Schulz, I would define `IPostRepository` into a separate class library. Then the business layer will know about this class library (containing only repository abstractions) and not the actual data access implementation which will of course also reference it. This way the business layer should never know anything about the specific implementation of your repositories and the specific data access layer should never know about the business layer. All they know about is the third class library containing `IPostRepository` and that's all they need. – Darin Dimitrov Jun 05 '11 at 18:11
  • The repository class needs to know about *Data Access* since the `DbContext` is defined there ... Wouldn't it be better to merge *Business* and *DataAccess*? – Marius Schulz Jun 05 '11 at 18:13
  • 1
    @Marius Schulz, yes `PostRepository` should know about `DbContext` => this is done in the specific class library which provides data access layer using Entity Framework. Tomorrow when you switch to NHibernate you will write a NHibernateDao.dll in which you will define `PostRepository` which will depend on NHs `ISession`. Both will implement `IPostRepository` which could be defined in a separate class library which will also be referenced by your business layer. The business layer should only know about the `IPostRepository` interface and never know anything about a specific `PostRepository`. – Darin Dimitrov Jun 05 '11 at 18:16
  • Thank you for your detailed elaborations! I will structure my application in the described way and see if I can get the whole thing running ... – Marius Schulz Jun 05 '11 at 18:25
  • 1
    Although the MVC assembly physically references all other projects, the MVC project logically does not know anything about the other projects and that's what matters. Only your composition root (the Application_Start) knows about all other project, and it happens to be in the MVC project. – Steven Jun 05 '11 at 19:50
  • @Steven: Thanks for distinguishing between physical and logical references! – Marius Schulz Jun 05 '11 at 21:53
  • I have updated my initial post and have provided a diagram of the dependencies of the solution's projects. Hope that helps! – Marius Schulz Jun 05 '11 at 21:57
  • @Darin: I am going to write another presentation layer (Silverlight project). How does this project know about the bound dependencies? – Marius Schulz Jun 06 '11 at 18:10
0

You have to ask yourself one thing: "do I really need 4 different assemblies for my MVC project?" You should break the code into assemblies according to deployment boundaries, not just based on some vague notion that Model code should be physically separate from Business code & similar. You should use namespaces for such things instead of separate projects.

Here's a good article on this issue: Advices on partitioning code through .NET assemblies by Patrick Smacchia.

Igor Brejc
  • 18,714
  • 13
  • 76
  • 95
  • You are right — for a simple web MVC project, 4 projects would definitely be an overkill. The point is that I will be adding a Silverlight project that needs to access the same *Business*, *DataAccess* and *Models* projects. – Marius Schulz Jun 06 '11 at 15:51
  • @Marius: OK, but that doesn't mean you need to split Business, DataAccess and Models into separate assemblies. You must also consider the speed of loading of these assemblies, especially for targets like Silverlight. You need 3 assemblies at most: one for your business engine, one for MVC front-end and one for Silverlight front-end. – Igor Brejc Jun 06 '11 at 16:03