1

So i'm using Autofac in my application that looks as follow (from top -down approach).

The project is in MVC 4 and i added the AutoFac.MVC4 beta.

  • Web App Client (the web application - presentation layer): namespace = AppBase.Web
  • Web App Core (eg. various actionresults, ...): namespace = AppBase.Web.Core
  • Services (eg. AuthenticationService, MemberService, TaskService): namespace = AppBase.Service
  • Data (includes Repositories, ...): namespace = AppBase.Data
  • Domain (POCO objects for Code Fist): namespace = AppBase.Domain

I included Autofac in my Web App Client with the following initialization code (for now):

public void RegisterContainersUsingAutofac()
    {
        var builder = new ContainerBuilder();
        builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
        builder.RegisterModelBinderProvider();
        builder.RegisterControllers(typeof(MvcApplication).Assembly);

        IContainer container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    }

Web App Client references the core, domain and services layer. The Service layer references the Data layer (for Repositories).

I have an interface in my data layer called iRepository, all my Repositories implement these

I'm wondering, what code should i add to my "RegisterContainersUsingAutofac" method, to automaticly (in a generic way) add all Repositories and Services, so i shouldn't add them myselve everytime. Keep in mind, the datalayer isn't referenced (i can, but i don't think it should).

PS. I used Unity in the past, but i like the generic methods that AutoFac has (in one project, i have over +/-180 lines with adding repositories and services, so this is something i don't want anymore).

Steven
  • 166,672
  • 24
  • 332
  • 435
NicoJuicy
  • 3,435
  • 4
  • 40
  • 66

2 Answers2

2

I was also using Unity.Mvc up until recently and switched over to Autofac. My issue with Unity.Mvc was that for no reason out of the blue, it would work one minute and not the next, it seemed very unstable.

Autofac has been a breeze to use and configure and I haven't had a single issue with it since I started using it.

I use WebActivator, so most of my configuration stuff are in their own classes as bootstrapper objects instead of littering the Global.asax file with a bunch of code.

Here is the (VB.NET) code below for the Autofac bootstrapper. You'll see that originally I had each service object and each repository object registered in that file, but they are now commented out and I use the auto registration functionality instead.

The project is using Mvc4.

#Region "Imports"

Imports System.Reflection
Imports Autofac
Imports Autofac.Integration.Mvc
Imports MyCompany.Data.Interfaces
Imports MyCompany.Data.Repositories
Imports MyCompany.Services
Imports MyCompany.Services.Interfaces
Imports MyCompany.Web.Mvc.Public.Bootstrap
Imports MyCompany.Web.Mvc.Public.Services

#End Region

#Region "Assembly Meta"

' This tells the app to run the "Start" method prior to running the App_Start method in Global.asax
<Assembly: WebActivator.PreApplicationStartMethod(GetType(AutofacDI), "Initialize")> 

#End Region

Namespace MyCompany.Web.Mvc.Public.Bootstrap

    ''' <summary>
    ''' Class to setup dependency injection and register types/services.
    ''' </summary>
    ''' <remarks></remarks>
    Public NotInheritable Class AutofacDI

        ''' <summary>
        ''' Method to register the Autofac dependency injection component.
        ''' </summary>
        ''' <remarks>
        ''' This line of code below could alternatively be placed in Global.asax App_Start(), doing
        ''' so in this manner ensures that this gets run "PreStart".
        ''' </remarks>
        Public Shared Sub Initialize()

            ' Create Unity dependency container.
            Dim dependencyContainer = BuildIocContainer()

            ' Set DI resolver
            DependencyResolver.SetResolver(New AutofacDependencyResolver(dependencyContainer))

        End Sub

        ''' <summary>
        ''' Registers the IOC types/services.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Shared Function BuildIocContainer() As Autofac.IContainer

            Dim builder = New ContainerBuilder

            With builder
                ' Register Controllers
                .RegisterControllers(Assembly.GetExecutingAssembly())

                ' Custom MyCompany/Mvc objects
                .RegisterType(Of FormsAuthenticationService)().As(Of IFormsAuthenticationService)().InstancePerHttpRequest()
                .RegisterType(Of AccountMembershipService)().As(Of IMembershipService)().InstancePerHttpRequest()

                '***************************************************************
                '*  MyCompany service objects.
                '***************************************************************
                ' This is auto registration, it replaces all the individual registration lines of code below.
                builder.RegisterAssemblyTypes(GetType(CatalogCodeService).Assembly).
                    Where(Function(t) t.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerHttpRequest()

                '.RegisterType(Of CatalogCodeService)().As(Of ICatalogCodeService)().InstancePerHttpRequest()
                '.RegisterType(Of ChargeCodeService)().As(Of IChargeCodeService)().InstancePerHttpRequest()
                '.RegisterType(Of CommentsService)().As(Of ICommentsService)().InstancePerHttpRequest()
                '.RegisterType(Of CommissionService)().As(Of ICommissionService)().InstancePerHttpRequest()
                '.RegisterType(Of ConfigCriteriaService)().As(Of IConfigCriteriaService)().InstancePerHttpRequest()
                '.RegisterType(Of ConfigGroupService)().As(Of IConfigGroupService)().InstancePerHttpRequest()
                '.RegisterType(Of ConfigQuestionService)().As(Of IConfigQuestionService)().InstancePerHttpRequest()
                '.RegisterType(Of ContactService)().As(Of IContactService)().InstancePerHttpRequest()
                '.RegisterType(Of CustomerProductItemService)().As(Of ICustomerProductItemService)().InstancePerHttpRequest()
                '.RegisterType(Of CustomerService)().As(Of ICustomerService)().InstancePerHttpRequest()
                '.RegisterType(Of OrderItemService)().As(Of IOrderItemService)().InstancePerHttpRequest()
                '.RegisterType(Of OrderService)().As(Of IOrderService)().InstancePerHttpRequest()
                '.RegisterType(Of PriceBreakService)().As(Of IPriceBreakService)().InstancePerHttpRequest()
                '.RegisterType(Of PriceService)().As(Of IPriceService)().InstancePerHttpRequest()
                '.RegisterType(Of ProductItemService)().As(Of IProductItemService)().InstancePerHttpRequest()
                '.RegisterType(Of QuoteItemService)().As(Of IQuoteItemService)().InstancePerHttpRequest()
                '.RegisterType(Of QuoteService)().As(Of IQuoteService)().InstancePerHttpRequest()
                '.RegisterType(Of ShipmentItemService)().As(Of IShipmentItemService)().InstancePerHttpRequest()
                '.RegisterType(Of ShipmentService)().As(Of IShipmentService)().InstancePerHttpRequest()
                '.RegisterType(Of ShoppingCartItemService)().As(Of IShoppingCartItemService)().InstancePerHttpRequest()
                '.RegisterType(Of ShoppingCartService)().As(Of IShoppingCartService)().InstancePerHttpRequest()
                '.RegisterType(Of SystemTableItemService)().As(Of ISystemTableItemService)().InstancePerHttpRequest()

                '***************************************************************
                '*  MyCompany repository objects (used by service objects above)
                '***************************************************************
                ' This is auto registration, it replaces all the individual registration lines of code below.
                builder.RegisterAssemblyTypes(GetType(CatalogCodeRepository).Assembly).
                    Where(Function(t) t.Name.EndsWith("Repository")).AsImplementedInterfaces().InstancePerHttpRequest()

                '.RegisterType(Of CatalogCodeRepository)().As(Of ICatalogCodeRepository)().InstancePerHttpRequest()
                '.RegisterType(Of ChargeCodeRepository)().As(Of IChargeCodeRepository)().InstancePerHttpRequest()
                '.RegisterType(Of CommentsRepository)().As(Of ICommentsRepository)().InstancePerHttpRequest()
                '.RegisterType(Of CommissionRepository)().As(Of ICommissionRepository)().InstancePerHttpRequest()
                '.RegisterType(Of ConfigCriteriaRepository)().As(Of IConfigCriteriaRepository)().InstancePerHttpRequest()
                '.RegisterType(Of ConfigGroupRepository)().As(Of IConfigGroupRepository)().InstancePerHttpRequest()
                '.RegisterType(Of ConfigQuestionRepository)().As(Of IConfigQuestionRepository)().InstancePerHttpRequest()
                '.RegisterType(Of ContactRepository)().As(Of IContactRepository)().InstancePerHttpRequest()
                '.RegisterType(Of CustomerProductItemRepository)().As(Of ICustomerProductItemRepository)().InstancePerHttpRequest()
                '.RegisterType(Of CustomerRepository)().As(Of ICustomerRepository)().InstancePerHttpRequest()
                '.RegisterType(Of IOrderItemRepository)().As(Of IOrderItemRepository)().InstancePerHttpRequest()
                '.RegisterType(Of OrderRepository)().As(Of IOrderRepository)().InstancePerHttpRequest()
                '.RegisterType(Of PriceBreakRepository)().As(Of IPriceBreakRepository)().InstancePerHttpRequest()
                '.RegisterType(Of PriceRepository)().As(Of IPriceRepository)().InstancePerHttpRequest()
                '.RegisterType(Of ProductItemRepository)().As(Of IProductItemRepository)().InstancePerHttpRequest()
                '.RegisterType(Of QuoteItemRepository)().As(Of IQuoteItemRepository)().InstancePerHttpRequest()
                '.RegisterType(Of QuoteRepository)().As(Of IQuoteRepository)().InstancePerHttpRequest()
                '.RegisterType(Of ShipmentItemRepository)().As(Of IShipmentItemRepository)().InstancePerHttpRequest()
                '.RegisterType(Of ShipmentRepository)().As(Of IShipmentRepository)().InstancePerHttpRequest()
                '.RegisterType(Of ShoppingCartItemRepository)().As(Of IShoppingCartItemRepository)().InstancePerHttpRequest()
                '.RegisterType(Of ShoppingCartRepository)().As(Of IShoppingCartRepository)().InstancePerHttpRequest()
                '.RegisterType(Of SystemTableItemRepository)().As(Of ISystemTableItemRepository)().InstancePerHttpRequest()
            End With

            Return builder.Build()

        End Function

    End Class

End Namespace

As you can see, the Autofac auto registration capability replaced over 40 lines of code that was needed using Unity.Mvc (I left those lines in and commented them to highlight)!!

Enjoy!!

Ed DeGagne
  • 3,250
  • 1
  • 30
  • 46
  • Just a small question. Where my global.asax.cs is, i haven't got a reference to my Data layer, but my service layer references the data layer. How can i add the repositories then ? Because the DDD design would forbid me from adding the data layer, as it doesn't expose any services. – NicoJuicy Jun 07 '12 at 19:07
  • Not sure of the implemented architecture you're using. In my case, my datalayer is my Repository library. In order for DI to work, you still need to add a reference to your UI project to the datalayer. If you're going to use DI, the calling application (UI in this case) needs to define WHAT to inject when it comes across an interface. The service layer has no place to define that on startup, the UI does that. So a reference to the datalayer (Repository) is needed in the calling application. No where does the UI call any repository methods, that takes place in the services layer. – Ed DeGagne Jan 15 '16 at 16:18
1

Have you considered using naming convention? http://code.google.com/p/autofac/wiki/Scanning

var assemblyToScan = Assembly.GetExecutingAssembly();

builder.RegisterAssemblyTypes(assemblyToScan)
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces();

builder.RegisterAssemblyTypes(assemblyToScan)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces();

You can also register using base types as covered in this post Autofac Scanning Assemblies for certain class type

Community
  • 1
  • 1
Mark Jones
  • 12,156
  • 2
  • 50
  • 62
  • Exactly what was posted below in my answer, auto registration is a very nice feature. – Ed DeGagne Jun 06 '12 at 20:28
  • 1
    Sorry Ed - I didn't see that at first glance amongst all the commented out lines, otherwise would have just added a comment about also using the Base type scanning... also worth looking at using generics for some of the repositories I tend to use this to register generics e.g. builder.RegisterGeneric(typeof(NHibernateRepository<>)).As(typeof(IRepository<>)); not always suitable but meets the needs of most repositories. – Mark Jones Jun 07 '12 at 14:18
  • Just a small question. Where my global.asax.cs is, i haven't got a reference to my Data layer, but my service layer references the data layer. How can i add the repositories then ? Because the DDD design would forbid me from adding the data layer, as it doesn't expose any services. – NicoJuicy Jun 07 '12 at 19:19
  • Hi there. You could try Replacing the first line of my example with var assembliesToScan = AppDomain.CurrentDomain.GetAssemblies(); Note the change to a plural on the variable name. I believe this will get all assemblies in memory for this app so your data layer should be included even if not directly referenced. If this doesn't work we could also look at using the "Module" feature in Autofac to then treat your data layer as a module that self registers... http://code.google.com/p/autofac/wiki/StructuringWithModules – Mark Jones Jun 11 '12 at 16:51
  • 1
    Sorry just to clarify - widening the scan still won't allow you to reference by type or or use the Generics approach - but MAY allow you to use the naming convention method. Personally I normally "break" the rules and reference the DAL just to register the types. I think if you want to be pure about it the Module approach as linked to above is your best route forward. – Mark Jones Jun 11 '12 at 17:03