1

I need to run a heavy code parallel to other code so that user don't have to wait .. I am trying Task.Run(() => to accomplish my task. My task is calling method from service using dependency injection.
I am getting following error:

{"Resolution of the dependency failed, type = \"Company.CacheProvider.CacheEmployeeProvider\", name = \"(none)\".\r\nException occurred while: while resolving.\r\nException is: InvalidOperationException - The PerRequestLifetimeManager can only be used in the context of an HTTP request. Possible causes for this error are using the lifetime manager on a non-ASP.NET application, or using it in a thread that is not associated with the appropriate synchronization context.\r\n-----------------------------------------------\r\nAt the time of the exception, the container was:\r\n\r\n Resolving Company.Provider.CacheProvider.CacheEmployeeProvider,(none)\r\n Resolving parameter \"cache\" of constructor Company.Provider.CacheProvider.CacheEmployeeProvider(Company.Provider.Interface.IEmployeeProvider provider, Company.Provider.Interface.ICache cache)\r\n Resolving Company.Provider.CacheProvider.RequestCache,(none) (mapped from Company.Provider.Interface.ICache, (none))\r\n"}

Error is providing the possible reason .. but I am not able to find the solution ..

Entire application is using PerRequestLifetimeManager .. how can I use it in may task .. or how can I make my task run in different context without any issue ..

UPDATE : - Registration

 var container = new UnityContainer();   

 container.RegisterType<IEmployeeProvider>(new InjectionFactory(unity => unity.Resolve<CacheEmployeeProvider>(new DependencyOverride(typeof(IEmployeeProvider), unity.Resolve<DbEmployeeProvider>()))));       
 container.RegisterType<IEmployeeService, EmployeeService>();

 DependencyResolver.SetResolver(new UnityDependencyResolver(container));
 DynamicModuleUtility.RegisterModule(typeof(Microsoft.Practices.Unity.Mvc.UnityPerRequestHttpModule));

Here is the base code of EmployeeController

Dependency

[Microsoft.Practices.Unity.Dependency]
public Lazy<IEmployeeService> EmployeeService { get; set; }

Post Request

[HttpPost]
public ActionResult AddEmployee(EmployeeModel model)
{
   var employee = EmployeeService.Value.Add(model);

   Task.Run(() => SetupEmployeeArea(employee.Id)); //task to setup employee related data

   return RedirectToAction("EmployeeList"); //redirect user to the list of employees
}

Task

async Task SetupEmployeeArea(int id)
{
   EmployeeService.Value.EmployeeSetup(id); //this call firing exception
}

I also tried following , but this code is not executing completely .. while debugging I lost the pointer in middle and nothing happening.

async Task SetupEmployeeArea(int id)
{
   var employeeService = DependencyResolver.Current.GetService<IEmployeeService>();
   employeeService.EmployeeSetup(id); //not getting any exception and code is also not running
}

Please share suggestions ... or if possible please also share best alternates to fulfill my requirement (run heavy code parallel) except "Hangfire" .. I already have too much load on that :)

2
  • Can you show the registration of EmployeeService? Commented Mar 16, 2018 at 9:23
  • @john added, please see update Commented Mar 16, 2018 at 9:43

1 Answer 1

2

The problem is that the http context closes before the task is completed. Try to make the controller's method async and run the task like:

await Task.Run(() => SetupEmployeeArea(employee.Id)); //task to setup employee related data

Then the task finishes before the http context is closed.

If you would like to return a result before the task is finished consider using some background worker for this like QueueBackgroundWorkItem https://blogs.msdn.microsoft.com/webdev/2014/06/04/queuebackgroundworkitem-to-reliably-schedule-and-run-background-processes-in-asp-net/ or some external framework like Hangfire and register your dependency to be resolved outside the http context.

If there is no need for some services to be resolved inside the http context change it scope to another e.g. transient or singleton https://msdn.microsoft.com/en-us/library/ff647854.aspx. You can always create custom lifetime manager that handles cases when the http context is closed like this: https://stackoverflow.com/a/4698138/9502162.

Another approach is to load the page and then use ajax call to perform this task so then users will see the page immediately. But with this approach you make client app responsible for setting employee related data which may be unwanted.

Sign up to request clarification or add additional context in comments.

10 Comments

can you please share some useful links?
To perform an ajax call I have to pass all the required parameter to the redirected view ... I have millions of users .. what can be the best way to pass parameters without clashing the users data
You only need employeeId for SetupEmployeeArea. I've added suggested solution to the answer
I'm glad I could help
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.