Resolve from root lifetime scope

1,855 views
Skip to first unread message

Paul Stovell

unread,
Apr 7, 2011, 8:00:37 AM4/7/11
to aut...@googlegroups.com
We have an ASP.NET application that lets users kick off relatively short "background tasks" (Windows Services aren't an option). 

A background task starts a new thread, and the thread runs for a while (reporting back to a database as it progresses). 

Since we're in the ASP.NET world, we use a lifetime scope per HTTP request. Currently the lifetime scopes look nested like this:

Root
  -> HTTP request
  -----> Background thread

The background thread might resolve objects like ISession or other components as it runs. Of course, since the HTTP request could complete before the thread does, this means Autofac throws because the parent scope is disposed before the child. 

The correct way (I think) is to structure our scopes like this:

Root
  -> HTTP request
  -> Background thread

To create child lifetime scopes, I've usually just injected ILifetimeScope, then called BeginLifetimeScope. Since the background thread is created during the HTTP request, that creates the nested scope. 

Is is possible to get the "root" lifetime scope injected? What would be a *nice* way to accomplish this?

Regards,

Paul Stovell

Nicholas Blumhardt

unread,
Apr 7, 2011, 5:49:41 PM4/7/11
to aut...@googlegroups.com
Hi Paul,

The brute force way to do this is to take a dependency on ILifetimeScope, then down-cast it to ISharingLifetimeScope (http://api.autofac.org/html/260FE584.htm).

ISharingLifetimeScope has ParentLifetimeScope and RootLifetimeScope properties - it is the interface used internally when searching for an appropriate scope up the "tree".

To make it slightly more palatable you might add:

builder.Register(c => (ISharingLifetimeScope)c.Resolve<ILifetimeScope>())
   .As<ISharingLifetimeScope>()
   .ExternallyOwned();


...so that the container provides it (we don't by default, because it encourages hacks like the above, keep reading... :))

A better and cleaner way to do this is to create a SingleInstance() component that acts as a factory for your background tasks:

class BackgroundTaskFactory
{
   public BackgroundTaskFactory(/* ILifetimeScope or a relationship type */) { }

   public void StartTask(/* Action, or a task spec.. */) {
       // Create a new lifetime to run the task in
   }
}

Because you register BackgroundTaskFactory as single instance, the injected ILifetimeScope will be the root one, and you can create direct children off of it. If you take something more like Func<Owned<ITask>> then the owned instances will be in child scopes of the root automatically.

Request-level components that take a dependency on BackgroundTaskFactory will naturally get the same shared instance up at the root level.

I think the second option is better, first is included just in case you need to whack something together in a hurry :)

Hope this helps,
Nick


--
You received this message because you are subscribed to the Google Groups "Autofac" group.
To post to this group, send email to aut...@googlegroups.com.
To unsubscribe from this group, send email to autofac+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/autofac?hl=en.

Paul Stovell

unread,
Apr 7, 2011, 7:59:51 PM4/7/11
to Nicholas Blumhardt, aut...@googlegroups.com
Thanks for the reply Nick. I had thought about a singleinstance component, but then thought the LifetimeScope it got might be the request scope depending on when it is created. But thinking it through, it makes sense that SingleInstance components would be resolved from the root lifetime scope, since we rely on that behaviour for ISessionFactory. Pretty obvious now. Thanks!

(+1 on not registering ISharedLifetimeScope, even injecting ILifetimeScope feels like a hack)

Sent from my Windows Phone

From: Nicholas Blumhardt
Sent: Friday, 8 April 2011 7:50 AM
To: aut...@googlegroups.com
Subject: Re: Resolve from root lifetime scope

Reply all
Reply to author
Forward
0 new messages