2

Problem:

I am building a four layer system with Ui, ServiceLayer, BizLayer and DataLayer. In line with good practice the ServiceLayer hides the BizLayer and DataLayer from the Ui, and of course the ServiceLayer doesn't know what the Ui Layer is.

My implementation is a single .NET application with each layer in its own assembly. I am using Autofac.MVC3 in my MVC3 Ui layer to do all the resolving classes used in a web request. I also include standard Autofac in my ServiceLayer so that it can handle the registration of all other layers in my application. At system startup I call a method to register all the types with Autofac. This does:

  1. Register the lower levels by calling a module inside the ServiceLayer. That handles the registration of itself and all other assemblies using the standard NuGet Autofac package.
  2. Then the Ui layer uses the NuGet Autofac.MVC package to register the various controllers and the IActionInvoker for Action Method injection.

My UnitOfWork class in my DataLayer is currently registered with InstancePerLifetimeScope because it is registered by the ServiceLayer which uses plain Autofac and knows nothing about InstancePerHttpRequest. However I read here that I should use InstancePerHttpRequest scope.

Question:

My question is, can I pass a lifetime scope around, i.e. could the MVC layer pass the InstancePerHttpRequest down to the service layer to use where needed? Alex Meyer-Gleaves seemed to suggest this was possible in his comment from this post below:

It is also possible to pass your own ILifetimeScopeProvider implementation to the AutofacDependencyResolver so that you can control the creation of lifetime scopes outside of the ASP.NET runtime

However the way he suggests seems to be MVC specific as ILifetimeScopeProvider is a MVC extension class. Can anyone suggest another way or is InstancePerLifetimeScope OK?

Community
  • 1
  • 1
Jon P Smith
  • 2,391
  • 1
  • 30
  • 55
  • How separate are your layers? Is the "service layer" a separate application or are all these things in the same application/AppDomain? (If they're separated by AppDomain, you'll have a tough time passing anything.) How do you currently resolve things in your application? The only reason you'd generally need to pass a lifetime scope is if you're doing service location, which is somewhat of an anti-pattern. – Travis Illig Jun 13 '12 at 16:14

2 Answers2

0

InstancePerHttpRequestScope is in fact a variant of InstantPerLifetimeScope. The first one only works in a request. If you want to execute some stuff on a background thread, it won't be available.

Like you I'm using autofac in as.net mvc and multiple app layers. I pass around the Container itself for the cases where I need to have a lifetime scope. I have a background queue which executes tasks. Each taks pretty much needs to have its own scope and to be exdecuted in a transaction. The Queue has an instance of IContainer (which is a singleton) and for every task, it begins a new scope and executes the task.

Db access and all are setup as INstancePerLifetimeScope in order to work in this case and I don't have aproblem when I use them in a controller.

MikeSW
  • 16,140
  • 3
  • 39
  • 53
  • Thanks Mike for your comments. In the case I was thinking about the calls to the persistence layer UnitOfWork are part of the HTTPRequest, e.g. something like the user inputting data that is written to the database. It looks like InstancePerLifetimeScope will work (although I am still in unit test mode so not absolutely sure yet) but Travis Illig post I mentioned in my question does state that you should use InstancePerHttpRequest. I was just seeing if there is a way to pass the InstancePerHttpRequest lifetime scope down to the lower layer to use. – Jon P Smith Jun 13 '12 at 14:28
  • I don't agree withe the fact that you HAVE TO use it. If you want to use the same container outside the http request, it won't work. You can't pass down the InstancePerHttpRequest since the scope wraps everything executed in a request, including db stuff. If you are certain you won't use the Container outside the request, you can use InstancePerHttpRequest without any problem. – MikeSW Jun 13 '12 at 16:35
  • Thanks MikeSW, I think you are right. I have been pointed to a post [here](https://groups.google.com/forum/#!topic/autofac/MnJUAMGSb1I/discussion) which I read as saying that InstancePerLifetimeScope is "In the case of MVC this is always the special HTTP request lifetime scope.". I will go with that. – Jon P Smith Jun 14 '12 at 13:18
0

With the help of MikeSW, Cecil Philips and Travis Illig (thanks guys) I have been put on the right track. My reading of the various posts, especially Alex Meyer-Gleaves post here, it seems that InstancePerLifetimeScope is treated as InstancePerHttpRequest when resolved by the Autofac.MVC package, within certain limitations (read Alex's post for what those limitations they). Alex's comment is:

Using InstancePerHttpRequest ensures that the service is resolved from the correct lifetime scope at runtime. In the case of MVC this is always the special HTTP request lifetime scope.

This means that I can safely register anything that needs a single instance for the whole htpp request as InstancePerLifetimeScope and it will work fine as long as I don't have child scoped items. That is fine and I can work with that.

Jon P Smith
  • 2,391
  • 1
  • 30
  • 55