Autofac, MVC 3 and Async Runner Problems.

1,468 views
Skip to first unread message

Fabricio Martinez

unread,
Mar 19, 2012, 7:44:56 PM3/19/12
to aut...@googlegroups.com
Hello,

I'm trying to setup a Async runner to use with an MVC project. The problem I have run into is that if I use DependencyResolver.Current.GetService() and pass a Repository object to the service it seems to die and I get an error saying the DBContext has gone out of scope. I also tried using AutofacDependecyResolver.Current.ApplicationContainer.BeginLifetimeScope() and with this one I get an error of "No scope with a Tag matching 'httpRequest' is visible from the scope in which the instance was requested."

What I have is the following:
AsynRunner:

public class DefaultAsyncRunner : IAsyncRunner

{

    public void Run<T>(Action<T> action)

    {

       Task.Factory.StartNew(delegate

       {

           using (var container = AutofacDependencyResolver.Current.ApplicationContainer.BeginLifetimeScope())

           {

               var service = container.Resolve<T>();

               action(service);

           }


      });

   }

}

WCComunicator:

public class WCComunicator

{

   readonly IPaisRepository paisRepository;


   public WCComunicator(IPaisRepository paisRepository)

   {

      this.paisRepository = paisRepository;

   }


   public void DoSomething()

  {

            List<Pais> paises = this.paisRepository.GetAll().ToList();

   }

}


Bootstrapper:

 var builder = new ContainerBuilder();

 builder.RegisterControllers(Assembly.GetExecutingAssembly());

 builder.RegisterType<DefaultCommandBus>().As<ICommandBus>().InstancePerHttpRequest();

 builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerHttpRequest();

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


 builder.RegisterType<DefaultAsyncRunner>().As<IAsyncRunner>();

 builder.RegisterType<iSeguro.Web.Core.Common.WCComunicator>();


 builder.RegisterAssemblyTypes(typeof(PaisRepository).Assembly).Where(t => t.Name.EndsWith("PaisRepository")).AsImplementedInterfaces().InstancePerHttpRequest();

            

 var services = Assembly.Load("iSeguro.Domain");

 builder.RegisterAssemblyTypes(services).AsClosedTypesOf(typeof(ICommandHandler<>)).InstancePerHttpRequest();

 builder.RegisterAssemblyTypes(services).AsClosedTypesOf(typeof(IValidationHandler<>)).InstancePerHttpRequest();

 builder.RegisterType<DefaultFormsAuthentication>().As<IFormsAuthentication>().InstancePerHttpRequest();

 builder.RegisterFilterProvider();


 IContainer container = builder.Build();                  

           

 DependencyResolver.SetResolver(new AutofacDependencyResolver(container));


and finally code in my controller:

 public class HomeController : Controller

 {

    readonly IAsyncRunner async;


    public HomeController(IAsyncRunner async)

    {

       this.async = async;

    }


   public ActionResult Test()

   {

       async.Run<iSeguro.Web.Core.Common.WCComunicator>(c => c.DoSomething());

       return RedirectToAction("Index");

   }

}


Like i said. I was able to execute the DoSomething function if I used DependencyResolver.Current.GetService() with in the function but this seems to create a thread on its own where the IRepositoryPais services was not able to read from the IDatabaseFactory (DBContext).

Any help welcomed.

Also, what Im trying to do is have a Async runned execute a thread on its own from the controller. That way the action finishes and the new thread does no block execution of the web site. This thread has to have access to the repositories, EF and WCF services.

Cecil Phillip

unread,
Mar 19, 2012, 10:05:16 PM3/19/12
to aut...@googlegroups.com
I haven't really looked at your code in detail to be honest, but I know that creating background threads in ASP.NET applications can be somewhat unstable.
Check out the bullet points in this post http://goo.gl/zmx0k

I'm guessing you read the post on Andrew's blog here. I don't know if this is actually a recommended practice for running background tasks 

Fabricio Martinez

unread,
Mar 20, 2012, 5:36:44 AM3/20/12
to aut...@googlegroups.com
Note: The error I get when using DependencyResolver.Current.GetService() is the following.

The operation cannot be completed because the DbContext has been disposed.

I tried setting up the IPaisRepository object as InstancePerLifetimeScope() and InstancePerDependency() with no change in the outcome.

Alex Meyer-Gleaves

unread,
Mar 20, 2012, 10:03:23 AM3/20/12
to aut...@googlegroups.com

Hi Fabricio,


I assume you found the post below on running background tasks from MVC actions.


http://aboutcode.net/2010/11/01/start-background-tasks-from-mvc-actions-using-autofac.html


The code you posted is missing the tag for the lifetime scope that is created from the root container. See the “httpRequest” string parameter passed to the BeginLifetimeScope method below. That tag is the same one that gets applied through the InstancePerHttpRequest registration methods. This is being done so that the service registrations can be reused.


public void Run<T>(Action<T> action)

{

    Task.Factory.StartNew(delegate

    {

        using (var container = AutofacDependencyResolver.Current.ApplicationContainer.BeginLifetimeScope("httpRequest"))

        {

            var service = container.Resolve<T>();

            action(service);

        }

    });

}


Cheers,


Alex.


--
You received this message because you are subscribed to the Google Groups "Autofac" group.
To view this discussion on the web visit https://groups.google.com/d/msg/autofac/-/FNDYHk03pFoJ.
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.

Fabricio Martinez

unread,
Mar 20, 2012, 11:01:14 AM3/20/12
to aut...@googlegroups.com
Than you very much Alex that did it.
To unsubscribe from this group, send email to autofac+unsubscribe@googlegroups.com.

Alex Meyer-Gleaves

unread,
Nov 20, 2012, 8:08:53 AM11/20/12
to aut...@googlegroups.com, gurnan...@gmail.com
Hi Sunny,

Try replacing "httpRequest" with "AutofacWebRequest".

Cheers,

Alex.

On Tuesday, 20 November 2012 05:07:23 UTC+10, gurnan...@gmail.com wrote:
Hello Alex,

Seems like the API is not same in AutoFac 2.6.3.862. Can you please give the solution with latest API...

Thanks,
Sunny

Cecil Phillip

unread,
Dec 1, 2012, 11:58:30 AM12/1/12
to aut...@googlegroups.com, gurnan...@gmail.com
Are there any constants available so as to avoid using hard coded strings and resolve any further changes in the scope name?

Alex Meyer-Gleaves

unread,
Dec 1, 2012, 4:20:26 PM12/1/12
to aut...@googlegroups.com
There are internal ones but I was considering a helper to create a scope with correct tag for testing etc. I don't want to define a constant in one assembly (e.g. Web) and have the other two (MVC and Web API) reference that just for a constant.
To view this discussion on the web visit https://groups.google.com/d/msg/autofac/-/NeoW9HLwhsgJ.

Tuan Nguyen

unread,
May 26, 2014, 10:01:58 AM5/26/14
to aut...@googlegroups.com
Thanks Alex !
You save my life, it take me weeks to solve unstable autofac lifetime scope in my background thread.

I have tried many many ways, but none work, till your solution come.

Reply all
Reply to author
Forward
Message has been deleted
0 new messages