This project is read-only.

use different WorkContexts in different threads base on the same HttpContext

Topics: Core, Troubleshooting, Writing modules
Oct 9, 2014 at 10:05 AM
I'm using Orchard v1.7.3.
I have next situation to handle:
Browser requests data from Orchard, to get data I use Web Services and use BeginInvoke/EndInvoke pattern to run web service in parallel.
BUT I use IRepository and HttpContext in this parallel threads.
Is it possible to inject different instances of IDependencies in diff threads and how can I run this threads in the same HttpContext?
WorkContextAccessor.GetContext() returns WorkContext base on current HttpContext, I need diff WorkContext in order to get diff IDependencies in diff threads, but the same HttpContext.Current in this threads it is the problem.

Thanks in Advance.
Oct 10, 2014 at 9:51 PM
Unfortunately you can't use multiple work contexts in parallel during an http request since the HttpContext will already contain a work context. You could try to create an HttpContext with an empty Items yourself and supply it to CreateWorkContextScope() but I'm not sure.

See some info about the work context:

What are you trying to achieve?
Oct 12, 2014 at 1:53 AM
Edited Oct 12, 2014 at 1:56 AM
HttpContext.Current is a "thread-static" property, which means it's static, but the value is specific to a thread. The value is set only on the main thread that handles a request. If you spawn a thread manually (directly or using TPL tasks), you need to handle re-writing the property on your own (set the HttpContext.Current to proper value fetched from the main thread) when you set up the new thread. Otherwise the value will be null and all components that rely on HttpContext.Current existence will fail.
There are lots of resources and discussions about HttpContext.Current and multi-threading - just google for it.

Regarding WorkContexts. If you need multiple of those on different threads - don't use GetContext. Create new work context scope for each thread instead, use it and dispose when the thread finishes. This is how we do it in background tasks.
Oct 13, 2014 at 9:01 AM
Edited Oct 13, 2014 at 9:02 AM
Thanks for quick response!
I describe the purpose of this actions in my first message: I have a couple of services which I would like to run in parallel which would be faster than run them one after another, but my services use IRepository and other services which is not thread safe so I need to create new instances of this services in new thread. After investigation I came up with next solution, what possible problems do you see in it?
// Before starting new thread I fill TaskContext and pass it to the  ExecuteWithEnsuredWorkContext method in the new thread
        public class TaskContext
            public string CurrentCulture { get; private set; }
            public ISite CurrentSite { get; private set; }
            public IUser CurrentUser { get; set; }
            public HttpContextBase WorkContextHttpContext { get; private set; }
            public HttpContext HttpContext { get; private set; }

            public TaskContext(WorkContext workContext, HttpContext httpContext)
                CurrentCulture = workContext.CurrentCulture;
                CurrentSite = workContext.CurrentSite;
                CurrentUser = workContext.CurrentUser;
                WorkContextHttpContext = workContext.HttpContext;
                HttpContext = httpContext;

            public WorkContext Transcribe(WorkContext workContext)
                workContext.CurrentCulture = CurrentCulture;
                workContext.CurrentSite = CurrentSite;
                workContext.CurrentUser = CurrentUser;
                workContext.HttpContext = WorkContextHttpContext;

                return workContext;
// In new thread I call ExecuteWithEnsuredWorkContext method to create new WorkContext and fill related WorkContext data
        public static void ExecuteWithEnsuredWorkContext(this IWorkContextAccessor wca, TaskContext taskContext, Action action)
                EnsuredHttpContext.Current = taskContext.HttpContext; // In all code which will be executed in action() I will use EnsuredHttpContext.Current
                using (var wcScope = wca.CreateWorkContextScope())
                    var transactionManager = wcScope.Resolve<ITransactionManager>();
                    catch (Exception)
                        EnsuredHttpContext.Current = null;