Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can multiple Autofac lifetime scopes be specified on a registration?

I'm using the Autofac IoC container with the MVC4 add-on which provides the InstancePerHttpRequest lifetime scope. However within my project I have the web, web-api and background worker threads. In the following example I assume the InstancePerHttpRequest scope doesn't mean much when not originating from a web request.

builder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>()
    .InstancePerHttpRequest()

I'm wondering if it is possible to do something like the following example and have the container choose the most appropriate lifetime scope?

builder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>()
    .InstancePerHttpRequest()
    .InstancePerApiRequest()
    .InstancePerDependency();

In this case what I intend to happen is if the request originates from a web request then it will choose the InstancePerHttpRequest scope, if it originates from an webApi request it will choose the InstancePerApiRequest scope and if it is used by the application worker threads it will use the InstancePerDependency scope?

Any ideas if this or something similar is possible?
Thanks

like image 288
chriskopec Avatar asked May 29 '13 15:05

chriskopec


People also ask

What is lifetime scope instance?

Instance Per Lifetime ScopeThis scope applies to nested lifetimes. A component with per-lifetime scope will have at most a single instance per nested lifetime scope. This is useful for objects specific to a single unit of work that may need to nest additional logical units of work.

How do I register an Autofac interface?

Register by Type var builder = new ContainerBuilder(); builder. RegisterType<ConsoleLogger>(); builder. RegisterType(typeof(ConfigReader)); When using reflection-based components, Autofac automatically uses the constructor for your class with the most parameters that are able to be obtained from the container.

What is Autofac C#?

Autofac is an addictive IoC container for . NET. It manages the dependencies between classes so that applications stay easy to change as they grow in size and complexity. This is achieved by treating regular . NET classes as components.

What is AsImplementedInterfaces?

RegistrationExtensions. AsImplementedInterfaces MethodSpecifies that a type from a scanned assembly is registered as providing all of its implemented interfaces.


1 Answers

This question has some fairly heavy overlap with these:

  • Managing AutoFac lifetime scopes per session and request in asp.net mvc 3
  • Instance per matching lifetime scope, with default?
  • Autofac - Lifetime and modules
  • Autofac Lifetimes and the Default Provider within a Matching Lifetime Scope

You'll want to check those out for some ideas.

The short answer is: This sort of thing isn't supported out of the box. You'll need to do one of a couple of things.

Option: You could have a different container for the background threads. This wouldn't allow you to share application-level singletons, but that might be OK for your application.

Option: You could create two lifetime scopes off the container and do the different registrations as part of the call to BeginLifetimeScope. This would allow you to share application-level singletons and have different lifetime scopes for the same components in different contexts. It's a little harder to manage the registrations, though, and you'll need two different service locators (e.g., DependencyResolver) because each logical context would need to resolve from its own scope.

var builder = new ContainerBuilder();
builder.RegisterType<AppLevelSingleton>().SingleInstance();
var container = builder.Build();

// Create a nested lifetime scope for your background threads
// that registers things as InstancePerDependency, etc. Pass
// that scope to whatever handles dependency resolution on the thread.
var backgroundScope = container.BeginLifetimeScope(
  b => b.RegisterType<DatabaseFactory>()
        .As<IDatabaseFactory>()
        .InstancePerDependency());

// Create a nested lifetime scope for the web app that registers
// things as InstancePerHttpRequest, etc. Pass that scope
// as the basis for the MVC dependency resolver.
var webScope = container.BeginLifetimeScope(
  b => b.RegisterType<DatabaseFactory>()
        .As<IDatabaseFactory>()
        .InstancePerHttpRequest());
var resolver = new AutofacDependencyResolver(webScope);
DependencyResolver.SetResolver(resolver);

If you really wanted to get fancy with this option, you could implement a custom IContainer that can detect which context it's in and resolves things from the appropriate nested scope. This is how the multitenant Autofac support works. However, that's a much more involved solution so I'm not going to write that all out here. Check the Autofac source for the multitenant support for examples.

Option: You could use a "lowest common denominator" sort of registration like InstancePerDependency or InstancePerLifetimeScope and skip the notion of having a different lifetime for different parts of the application.

Note that, right now, technically, internally, there is no difference between what InstancePerHttpRequest and InstancePerWebApiRequest do. They both boil down to exactly the same thing and are effectively interchangeable. (I can't promise it'll always be that way forever, but I don't know why it would need to change.)

like image 155
Travis Illig Avatar answered Sep 23 '22 09:09

Travis Illig