1

Following the answer from this other post I am trying to configure autofac for both an ASP .Net MVC 5 project and a Web Api 2 one.

For the Web Api project I used the Autofac.Integration.WebApi library that I referenced it manually to the project and modified the Global.asax file like so:

public class WebApiApplication : HttpApplication
{
    protected void Application_Start()
    {
        ConfigureDiContainer();

        GlobalConfiguration.Configure(WebApiConfig.Register);
    }

    private static void ConfigureDiContainer()
    {
        var servicesAssembly = Assembly.GetExecutingAssembly();
        var container = BuildContainer(servicesAssembly);
        var resolver = new AutofacWebApiDependencyResolver(container);

        GlobalConfiguration.Configuration.DependencyResolver = resolver;
    }

    private static IContainer BuildContainer(Assembly servicesAssembly)
    {
        var x = new ActivityBl();

        var builder = new ContainerBuilder();

        builder.RegisterApiControllers(servicesAssembly);

        var appAssemblies = AppDomain.CurrentDomain
            .GetAssemblies()
            .Where(a => a.ToString().StartsWith("SC."))
            .ToArray();
        builder.RegisterAssemblyTypes(appAssemblies).AsImplementedInterfaces();
        builder.RegisterAssemblyTypes(servicesAssembly).AsImplementedInterfaces();

        return builder.Build();
    }
}

And when I run the services this works as expected.

For the MVC 5 project I installed the Autofac.Integration.Mvc library from NuGet and modified the Global.asax code as well:

public class MvcApplication : HttpApplication
{
    protected void Application_Start()
    {
        var builder = new ContainerBuilder();
        builder.RegisterControllers(typeof(MvcApplication).Assembly);
        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

The controllers in both projects have no default constructor, only the ones with the dependencies:

MVC Controller:

    private readonly IActivitiesService activitiesService;

    public HomeController(IActivitiesService activitiesService)
    {
        this.activitiesService = activitiesService;
    }

Web Api Controller:

public class ActivitiesController : ApiController, IActivitiesService
{
    private readonly IActivities activitiesBl;

    public ActivitiesController(IActivities activitiesBl)
    {
        if(activitiesBl == null) throw new ArgumentNullException("activitiesBl", "ActivitiesBl dependency was not properly created.");

        this.activitiesBl = activitiesBl;
    }
}

When I run the application I get the following error:

None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'SC.Web.Controllers.HomeController' can be invoked with the available services and parameters: Cannot resolve parameter 'SC.Services.ServiceContracts.IActivitiesService activitiesService' of constructor 'Void .ctor(SC.Services.ServiceContracts.IActivitiesService)'.

In a way I guess it makes sense since the IoC on the web project has no definitions for the services and it seems that it is trying to resolve the whole dependency tree which leads me to the following questions:

  1. From the names of the libraries it seems that each one is specifically tailored for each kind of project, is that so or can I use the Mvc one also for the Web Api?
  2. Have things changed in such a way that the recommendation I got from the previous post is no longer valid and now I must have all the definitions in the Composition Root for each client?
  3. What would be now the best way of configuring the dependencies hierarchy in this kind of multi-layered setup?

Thank you.

Community
  • 1
  • 1
Sergio Romero
  • 6,477
  • 11
  • 41
  • 71
  • Can you post the constructors for the classes implementing IActivitiesService and IActivities? Also can you confirm they are on the same assembly? – Juan Mar 06 '15 at 16:27
  • @Juan The IActivitiesService implementation is the Web Api controller, I updated that code to make it more explicit. The IActivities is just an empty shell for now but of course eventually will also have a constructor with dependencies on it. – Sergio Romero Mar 06 '15 at 16:33
  • Uhm, the reason you need to instantiate the class in the builders I guess is for the AppDomain to load the assembly so you can find it later when querying it for all loaded assemblies. The namespace of class Activities starts with SC. doesn't it? – Juan Mar 06 '15 at 16:39
  • 1
    @Juan Hahaha. Yes I figured that much. That's not the problem I'm asking about though. I guess I should remove that comment to avoid confusions. That was more for me than for the questions but it slipped through when I pasted the code :) – Sergio Romero Mar 06 '15 at 16:45

1 Answers1

0

I have many common dependencies coming from several projects, including Web Api (using the Web Api Autofac integration), Quartz Scheduling, unit tests, data migration console apps etc.

For this, I have been able to initiate the ContainerBuilder in the manner expected by the project and then I just pass it into some code that exists in a separate project to specify the shared dependencies.

You might have the following 3 projects

MyApp.WebApi

var builder = new ContainerBuilder();
builder.RegisterApiControllers(servicesAssembly);
CommonContainerConfig.RegisterDependencies(builder);

MyApp.Mvc5

var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
CommonContainerConfig.RegisterDependencies(builder);

MyApp.Common

public static class CommonContainerConfig
{
    public static void RegisterDependencies(ContainerBuilder builder) 
    {
        builder.RegisterType<ActivitiesService>().As<IActivitiesService>();
        //etc
    }
}

This works for my scenario, although I'm not 100% sure it's what you're after...

S. Baggy
  • 950
  • 10
  • 21