From 9bdf130cc9ec64a09cfd84afb2566475ccdf1060 Mon Sep 17 00:00:00 2001 From: jtkech Date: Tue, 20 Oct 2015 05:40:01 +0200 Subject: [PATCH 01/15] Update WorkContextAccessor.cs --- .../Environment/WorkContextAccessor.cs | 40 +++++++------------ 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/src/Orchard/Environment/WorkContextAccessor.cs b/src/Orchard/Environment/WorkContextAccessor.cs index e572d21f6..f878f6689 100644 --- a/src/Orchard/Environment/WorkContextAccessor.cs +++ b/src/Orchard/Environment/WorkContextAccessor.cs @@ -1,6 +1,6 @@ -using System; -using System.Collections.Concurrent; +using System; using System.Collections.Generic; +using System.Runtime.Remoting.Messaging; using System.Web; using Autofac; using Orchard.Logging; @@ -16,9 +16,6 @@ namespace Orchard.Environment { // this guarantees the correct accessor is being resolved. readonly object _workContextKey = new object(); - [ThreadStatic] - static ConcurrentDictionary _threadStaticContexts; - public WorkContextAccessor( IHttpContextAccessor httpContextAccessor, ILifetimeScope lifetimeScope) { @@ -30,8 +27,7 @@ namespace Orchard.Environment { if (!httpContext.IsBackgroundContext()) return httpContext.Items[_workContextKey] as WorkContext; - WorkContext workContext; - return EnsureThreadStaticContexts().TryGetValue(_workContextKey, out workContext) ? workContext : null; + return CallContext.LogicalGetData("WorkContext") as WorkContext; } public WorkContext GetContext() { @@ -39,8 +35,7 @@ namespace Orchard.Environment { if (!httpContext.IsBackgroundContext()) return GetContext(httpContext); - WorkContext workContext; - return EnsureThreadStaticContexts().TryGetValue(_workContextKey, out workContext) ? workContext : null; + return CallContext.LogicalGetData("WorkContext") as WorkContext; } public IWorkContextScope CreateWorkContextScope(HttpContextBase httpContext) { @@ -57,7 +52,6 @@ namespace Orchard.Environment { _workContextKey); } - public IWorkContextScope CreateWorkContextScope() { var httpContext = _httpContextAccessor.Current(); if (!httpContext.IsBackgroundContext()) @@ -68,18 +62,9 @@ namespace Orchard.Environment { var events = workLifetime.Resolve>(); events.Invoke(e => e.Started(), NullLogger.Instance); - return new ThreadStaticScopeImplementation( - events, - workLifetime, - EnsureThreadStaticContexts(), - _workContextKey); + return new CallContextScopeImplementation(events, workLifetime); } - static ConcurrentDictionary EnsureThreadStaticContexts() { - return _threadStaticContexts ?? (_threadStaticContexts = new ConcurrentDictionary()); - } - - class HttpContextScopeImplementation : IWorkContextScope { readonly WorkContext _workContext; readonly Action _disposer; @@ -113,19 +98,22 @@ namespace Orchard.Environment { } } - class ThreadStaticScopeImplementation : IWorkContextScope { + class CallContextScopeImplementation : IWorkContextScope { readonly WorkContext _workContext; readonly Action _disposer; - public ThreadStaticScopeImplementation(IEnumerable events, ILifetimeScope lifetimeScope, ConcurrentDictionary contexts, object workContextKey) { + public CallContextScopeImplementation(IEnumerable events, ILifetimeScope lifetimeScope) { _workContext = lifetimeScope.Resolve(); - contexts.AddOrUpdate(workContextKey, _workContext, (a, b) => _workContext); + CallContext.LogicalSetData("WorkContext", _workContext); + + CallContext.LogicalSetData("HttpContext", null); + var httpContext = lifetimeScope.Resolve(); + CallContext.LogicalSetData("HttpContext", httpContext); _disposer = () => { events.Invoke(e => e.Finished(), NullLogger.Instance); - - WorkContext removedContext; - contexts.TryRemove(workContextKey, out removedContext); + CallContext.FreeNamedDataSlot("WorkContext"); + CallContext.FreeNamedDataSlot("HttpContext"); lifetimeScope.Dispose(); }; } From afd80a8c727256a99e499287a66208909e9d4a36 Mon Sep 17 00:00:00 2001 From: jtkech Date: Tue, 20 Oct 2015 05:44:28 +0200 Subject: [PATCH 02/15] Update HttpContextAccessor.cs --- src/Orchard/Mvc/HttpContextAccessor.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Orchard/Mvc/HttpContextAccessor.cs b/src/Orchard/Mvc/HttpContextAccessor.cs index b13d6fe25..f2e35cbab 100644 --- a/src/Orchard/Mvc/HttpContextAccessor.cs +++ b/src/Orchard/Mvc/HttpContextAccessor.cs @@ -1,13 +1,16 @@ -using System; +using System; +using System.Runtime.Remoting.Messaging; using System.Web; namespace Orchard.Mvc { + public class HttpContextAccessor : IHttpContextAccessor { private HttpContextBase _httpContext; public HttpContextBase Current() { var httpContext = GetStaticProperty(); - return !IsBackgroundHttpContext(httpContext) ? new HttpContextWrapper(httpContext) : _httpContext; + return !IsBackgroundHttpContext(httpContext) ? new HttpContextWrapper(httpContext) : + _httpContext ?? CallContext.LogicalGetData("HttpContext") as HttpContextBase; } public void Set(HttpContextBase httpContext) { @@ -15,7 +18,7 @@ namespace Orchard.Mvc { } private static bool IsBackgroundHttpContext(HttpContext httpContext) { - return httpContext == null || httpContext.Items.Contains(BackgroundHttpContextFactory.IsBackgroundHttpContextKey); + return httpContext == null || httpContext.Items.Contains(MvcModule.IsBackgroundHttpContextKey); } private static HttpContext GetStaticProperty() { @@ -36,4 +39,4 @@ namespace Orchard.Mvc { return httpContext; } } -} \ No newline at end of file +} From 0384c55011e18ec1fa912d697976ab9acf5aba5a Mon Sep 17 00:00:00 2001 From: jtkech Date: Tue, 20 Oct 2015 05:46:40 +0200 Subject: [PATCH 03/15] Update MvcModule.cs --- src/Orchard/Mvc/MvcModule.cs | 125 +++++++++++++++++++++++------------ 1 file changed, 83 insertions(+), 42 deletions(-) diff --git a/src/Orchard/Mvc/MvcModule.cs b/src/Orchard/Mvc/MvcModule.cs index 9b289749d..c90c6b804 100644 --- a/src/Orchard/Mvc/MvcModule.cs +++ b/src/Orchard/Mvc/MvcModule.cs @@ -1,20 +1,23 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Globalization; +using System.IO; using System.Web; using System.Web.Caching; using System.Web.Instrumentation; using System.Web.Mvc; using System.Web.Routing; using Autofac; +using Orchard.Environment.Configuration; +using Orchard.Mvc.Extensions; using Orchard.Mvc.Routes; using Orchard.Settings; -using Orchard.Exceptions; namespace Orchard.Mvc { public class MvcModule : Module { + public const string IsBackgroundHttpContextKey = "IsBackgroundHttpContext"; protected override void Load(ContainerBuilder moduleBuilder) { moduleBuilder.RegisterType().InstancePerDependency(); @@ -24,37 +27,25 @@ namespace Orchard.Mvc { moduleBuilder.Register(UrlHelperFactory).As().InstancePerDependency(); } - private static bool IsRequestValid() { - if (HttpContext.Current == null) - return false; - - try { - // The "Request" property throws at application startup on IIS integrated pipeline mode. - var req = HttpContext.Current.Request; - } - catch (Exception ex) { - if (ex.IsFatal()) { - throw; - } - - return false; - } - - return true; - } - static HttpContextBase HttpContextBaseFactory(IComponentContext context) { - if (IsRequestValid()) { - return new HttpContextWrapper(HttpContext.Current); - } + + var httpContext = context.Resolve().Current(); + if (httpContext != null) + return httpContext; var siteService = context.Resolve(); + var prefix = context.Resolve().RequestUrlPrefix; // Wrapping the code accessing the SiteSettings in a function that will be executed later (in HttpContextPlaceholder), // so that the RequestContext will have been established when the time comes to actually load the site settings, // which requires activating the Site content item, which in turn requires a UrlHelper, which in turn requires a RequestContext, // thus preventing a StackOverflowException. - var baseUrl = new Func(() => siteService.GetSiteSettings().BaseUrl); + var baseUrl = new Func(() => { + var url = siteService.GetSiteSettings().BaseUrl; + return !string.IsNullOrWhiteSpace(url) ? !string.IsNullOrWhiteSpace(prefix) ? + url.TrimEnd('/') + "/" + prefix : url : "http://localhost" + + System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath; + }); var httpContextBase = new HttpContextPlaceholder(baseUrl); return httpContextBase; @@ -63,7 +54,8 @@ namespace Orchard.Mvc { static RequestContext RequestContextFactory(IComponentContext context) { var httpContextAccessor = context.Resolve(); var httpContext = httpContextAccessor.Current(); - if (httpContext != null) { + + if (!httpContext.IsBackgroundContext()) { var mvcHandler = httpContext.Handler as MvcHandler; if (mvcHandler != null) { @@ -76,7 +68,11 @@ namespace Orchard.Mvc { return hasRequestContext.RequestContext; } } - else { + else if (httpContext is HttpContextPlaceholder) { + if (((HttpContextPlaceholder)httpContext).IsResolved) + return httpContext.Request.RequestContext; + } + else if (httpContext == null) { httpContext = HttpContextBaseFactory(context); } @@ -90,7 +86,8 @@ namespace Orchard.Mvc { /// /// Standin context for background tasks. /// - public class HttpContextPlaceholder : HttpContextBase { + public class HttpContextPlaceholder : HttpContextBase, IDisposable { + private HttpContext _httpContext; private readonly Lazy _baseUrl; private readonly IDictionary _items = new Dictionary(); @@ -98,8 +95,35 @@ namespace Orchard.Mvc { _baseUrl = new Lazy(baseUrl); } + public void Dispose() { + _httpContext = null; + if (HttpContext.Current != null) + HttpContext.Current = null; + } + + public bool IsResolved { + get { + return _baseUrl.IsValueCreated; + } + } + public override HttpRequestBase Request { - get { return new HttpRequestPlaceholder(new Uri(_baseUrl.Value)); } + get { + + if (_httpContext == null) { + var httpContext = new HttpContext(new HttpRequest("", _baseUrl.Value, ""), new HttpResponse(new StringWriter())); + httpContext.Items[IsBackgroundHttpContextKey] = true; + _httpContext = httpContext; + } + + if (HttpContext.Current != _httpContext) + HttpContext.Current = _httpContext; + return new HttpRequestPlaceholder(this, new Uri(_baseUrl.Value)); + } + } + + public override HttpSessionStateBase Session { + get { return new HttpSessionStatePlaceholder(); } } public override IHttpHandler Handler { get; set; } @@ -129,6 +153,14 @@ namespace Orchard.Mvc { } } + public class HttpSessionStatePlaceholder : HttpSessionStateBase { + public override object this[string name] { + get { + return null; + } + } + } + public class HttpResponsePlaceholder : HttpResponseBase { public override string ApplyAppPathModifier(string virtualPath) { return virtualPath; @@ -145,12 +177,32 @@ namespace Orchard.Mvc { /// standin context for background tasks. /// public class HttpRequestPlaceholder : HttpRequestBase { + private HttpContextBase _httpContext; private readonly Uri _uri; - public HttpRequestPlaceholder(Uri uri) { + public HttpRequestPlaceholder(HttpContextBase httpContext, Uri uri) { + _httpContext = httpContext; _uri = uri; } + public override RequestContext RequestContext { + get { + return new RequestContext(_httpContext, new RouteData()); + } + } + + public override NameValueCollection QueryString { + get { + return new NameValueCollection(); + } + } + + public override string RawUrl { + get { + return _uri.OriginalString; + } + } + /// /// anonymous identity provided for background task. /// @@ -158,17 +210,6 @@ namespace Orchard.Mvc { get { return false; } } - /// - /// Create an anonymous ID the same way as ASP.NET would. - /// Some users of an HttpRequestPlaceHolder object could expect this, - /// say CookieCultureSelector from module Orchard.CulturePicker. - /// - public override string AnonymousID { - get { - return Guid.NewGuid().ToString("D", CultureInfo.InvariantCulture); - } - } - // empty collection provided for background operation public override NameValueCollection Form { get { @@ -278,4 +319,4 @@ namespace Orchard.Mvc { public override int ScriptTimeout { get; set; } } } -} \ No newline at end of file +} From fbd0f878f5c058ff35caa37d5ebfe54d1b72e484 Mon Sep 17 00:00:00 2001 From: jtkech Date: Tue, 20 Oct 2015 05:56:27 +0200 Subject: [PATCH 04/15] Update MvcModule.cs --- src/Orchard/Mvc/MvcModule.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Orchard/Mvc/MvcModule.cs b/src/Orchard/Mvc/MvcModule.cs index c90c6b804..40d00287a 100644 --- a/src/Orchard/Mvc/MvcModule.cs +++ b/src/Orchard/Mvc/MvcModule.cs @@ -210,6 +210,17 @@ namespace Orchard.Mvc { get { return false; } } + /// + /// Create an anonymous ID the same way as ASP.NET would. + /// Some users of an HttpRequestPlaceHolder object could expect this, + /// say CookieCultureSelector from module Orchard.CulturePicker. + /// + public override string AnonymousID { + get { + return Guid.NewGuid().ToString("D", CultureInfo.InvariantCulture); + } + } + // empty collection provided for background operation public override NameValueCollection Form { get { From d2ef174479587a47c4f0be44d6ccaf678a3bb4dc Mon Sep 17 00:00:00 2001 From: jtkech Date: Tue, 20 Oct 2015 05:59:40 +0200 Subject: [PATCH 05/15] Update HttpContextBaseExtensions.cs --- src/Orchard/Mvc/Extensions/HttpContextBaseExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Orchard/Mvc/Extensions/HttpContextBaseExtensions.cs b/src/Orchard/Mvc/Extensions/HttpContextBaseExtensions.cs index 9a7864887..81fb1932f 100644 --- a/src/Orchard/Mvc/Extensions/HttpContextBaseExtensions.cs +++ b/src/Orchard/Mvc/Extensions/HttpContextBaseExtensions.cs @@ -1,4 +1,4 @@ -using System.Web; +using System.Web; namespace Orchard.Mvc.Extensions { public static class HttpContextBaseExtensions { From 348461d41f0f54fd8d710edb3a495b1ccba8db54 Mon Sep 17 00:00:00 2001 From: jtkech Date: Thu, 29 Oct 2015 00:24:44 +0100 Subject: [PATCH 06/15] Update MvcModule.cs --- src/Orchard/Mvc/MvcModule.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Orchard/Mvc/MvcModule.cs b/src/Orchard/Mvc/MvcModule.cs index 40d00287a..994e54952 100644 --- a/src/Orchard/Mvc/MvcModule.cs +++ b/src/Orchard/Mvc/MvcModule.cs @@ -10,7 +10,6 @@ using System.Web.Instrumentation; using System.Web.Mvc; using System.Web.Routing; using Autofac; -using Orchard.Environment.Configuration; using Orchard.Mvc.Extensions; using Orchard.Mvc.Routes; using Orchard.Settings; @@ -34,18 +33,12 @@ namespace Orchard.Mvc { return httpContext; var siteService = context.Resolve(); - var prefix = context.Resolve().RequestUrlPrefix; // Wrapping the code accessing the SiteSettings in a function that will be executed later (in HttpContextPlaceholder), // so that the RequestContext will have been established when the time comes to actually load the site settings, // which requires activating the Site content item, which in turn requires a UrlHelper, which in turn requires a RequestContext, // thus preventing a StackOverflowException. - var baseUrl = new Func(() => { - var url = siteService.GetSiteSettings().BaseUrl; - return !string.IsNullOrWhiteSpace(url) ? !string.IsNullOrWhiteSpace(prefix) ? - url.TrimEnd('/') + "/" + prefix : url : "http://localhost" - + System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath; - }); + var baseUrl = new Func(() => siteService.GetSiteSettings().BaseUrl); var httpContextBase = new HttpContextPlaceholder(baseUrl); return httpContextBase; From a33471183fa13a3120627430a682e10ae8b89944 Mon Sep 17 00:00:00 2001 From: jtkech Date: Sun, 6 Dec 2015 05:18:48 +0100 Subject: [PATCH 07/15] Update MvcModule.cs --- src/Orchard/Mvc/MvcModule.cs | 78 ++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/src/Orchard/Mvc/MvcModule.cs b/src/Orchard/Mvc/MvcModule.cs index 994e54952..ae873540a 100644 --- a/src/Orchard/Mvc/MvcModule.cs +++ b/src/Orchard/Mvc/MvcModule.cs @@ -38,6 +38,7 @@ namespace Orchard.Mvc { // so that the RequestContext will have been established when the time comes to actually load the site settings, // which requires activating the Site content item, which in turn requires a UrlHelper, which in turn requires a RequestContext, // thus preventing a StackOverflowException. + var baseUrl = new Func(() => siteService.GetSiteSettings().BaseUrl); var httpContextBase = new HttpContextPlaceholder(baseUrl); @@ -45,8 +46,8 @@ namespace Orchard.Mvc { } static RequestContext RequestContextFactory(IComponentContext context) { - var httpContextAccessor = context.Resolve(); - var httpContext = httpContextAccessor.Current(); + + var httpContext = HttpContextBaseFactory(context); if (!httpContext.IsBackgroundContext()) { @@ -62,11 +63,7 @@ namespace Orchard.Mvc { } } else if (httpContext is HttpContextPlaceholder) { - if (((HttpContextPlaceholder)httpContext).IsResolved) - return httpContext.Request.RequestContext; - } - else if (httpContext == null) { - httpContext = HttpContextBaseFactory(context); + return ((HttpContextPlaceholder)httpContext).RequestContext; } return new RequestContext(httpContext, new RouteData()); @@ -81,6 +78,7 @@ namespace Orchard.Mvc { /// public class HttpContextPlaceholder : HttpContextBase, IDisposable { private HttpContext _httpContext; + private HttpRequestPlaceholder _request; private readonly Lazy _baseUrl; private readonly IDictionary _items = new Dictionary(); @@ -93,16 +91,18 @@ namespace Orchard.Mvc { if (HttpContext.Current != null) HttpContext.Current = null; } - - public bool IsResolved { - get { - return _baseUrl.IsValueCreated; - } - } public override HttpRequestBase Request { - get { + // Note: To fully resolve the baseUrl, some factories are needed (HttpContextBase, RequestContext...), + // so, doing this in such a factory creates a circular dependency (see HttpContextBase factory comments). + + // When rendering a view in a background task, an Html Helper can access HttpContext.Current directly, + // so, here we create a fake HttpContext based on the baseUrl, and use it to update HttpContext.Current. + // We cannot do this before in a factory (see note above), anyway, by doing this on each Request access, + // we have a better chance to maintain the HttpContext.Current state even with some asynchronous code. + + get { if (_httpContext == null) { var httpContext = new HttpContext(new HttpRequest("", _baseUrl.Value, ""), new HttpResponse(new StringWriter())); httpContext.Items[IsBackgroundHttpContextKey] = true; @@ -111,7 +111,24 @@ namespace Orchard.Mvc { if (HttpContext.Current != _httpContext) HttpContext.Current = _httpContext; - return new HttpRequestPlaceholder(this, new Uri(_baseUrl.Value)); + + if (_request == null) { + _request = new HttpRequestPlaceholder(this, _baseUrl); + } + return _request; + } + } + + internal RequestContext RequestContext { + + // Uses the Request object but without creating an HttpContext which would need to resolve the baseUrl, + // so, can be used by the RequestContext factory without creating a circular dependency (see note above). + + get { + if (_request == null) { + _request = new HttpRequestPlaceholder(this, _baseUrl); + } + return _request.RequestContext; } } @@ -171,28 +188,34 @@ namespace Orchard.Mvc { /// public class HttpRequestPlaceholder : HttpRequestBase { private HttpContextBase _httpContext; - private readonly Uri _uri; + private RequestContext _requestContext; + private readonly Lazy _baseUrl; + private readonly NameValueCollection _queryString = new NameValueCollection(); + private Uri _uri; - public HttpRequestPlaceholder(HttpContextBase httpContext, Uri uri) { + public HttpRequestPlaceholder(HttpContextBase httpContext, Lazy baseUrl) { _httpContext = httpContext; - _uri = uri; + _baseUrl = baseUrl; } public override RequestContext RequestContext { get { - return new RequestContext(_httpContext, new RouteData()); + if (_requestContext == null) { + _requestContext = new RequestContext(_httpContext, new RouteData()); + } + return _requestContext; } } public override NameValueCollection QueryString { get { - return new NameValueCollection(); + return _queryString; } } public override string RawUrl { get { - return _uri.OriginalString; + return Url.OriginalString; } } @@ -223,13 +246,16 @@ namespace Orchard.Mvc { public override Uri Url { get { + if (_uri == null) { + _uri = new Uri(_baseUrl.Value); + } return _uri; } } public override NameValueCollection Headers { get { - return new NameValueCollection { { "Host", _uri.Authority } }; + return new NameValueCollection { { "Host", Url.Authority } }; } } @@ -253,16 +279,16 @@ namespace Orchard.Mvc { public override string ApplicationPath { get { - return _uri.LocalPath; + return Url.LocalPath; } } public override NameValueCollection ServerVariables { get { return new NameValueCollection { - { "SERVER_PORT", _uri.Port.ToString(CultureInfo.InvariantCulture) }, - { "HTTP_HOST", _uri.Authority.ToString(CultureInfo.InvariantCulture) }, - + { "SERVER_PORT", Url.Port.ToString(CultureInfo.InvariantCulture) }, + { "HTTP_HOST", Url.Authority.ToString(CultureInfo.InvariantCulture) }, + }; } } From f3b3e0a7fb4c19364060409fc9a812c689430ed8 Mon Sep 17 00:00:00 2001 From: jtkech Date: Tue, 8 Dec 2015 20:54:53 +0100 Subject: [PATCH 08/15] Update WorkContextAccessor.cs --- src/Orchard/Environment/WorkContextAccessor.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Orchard/Environment/WorkContextAccessor.cs b/src/Orchard/Environment/WorkContextAccessor.cs index f878f6689..e9f2fc4db 100644 --- a/src/Orchard/Environment/WorkContextAccessor.cs +++ b/src/Orchard/Environment/WorkContextAccessor.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.Remoting; using System.Runtime.Remoting.Messaging; using System.Web; using Autofac; @@ -27,7 +28,8 @@ namespace Orchard.Environment { if (!httpContext.IsBackgroundContext()) return httpContext.Items[_workContextKey] as WorkContext; - return CallContext.LogicalGetData("WorkContext") as WorkContext; + var context = CallContext.LogicalGetData("WorkContext") as ObjectHandle; + return context != null ? context.Unwrap() as WorkContext : null; } public WorkContext GetContext() { @@ -35,7 +37,8 @@ namespace Orchard.Environment { if (!httpContext.IsBackgroundContext()) return GetContext(httpContext); - return CallContext.LogicalGetData("WorkContext") as WorkContext; + var context = CallContext.LogicalGetData("WorkContext") as ObjectHandle; + return context != null ? context.Unwrap() as WorkContext : null; } public IWorkContextScope CreateWorkContextScope(HttpContextBase httpContext) { @@ -104,11 +107,11 @@ namespace Orchard.Environment { public CallContextScopeImplementation(IEnumerable events, ILifetimeScope lifetimeScope) { _workContext = lifetimeScope.Resolve(); - CallContext.LogicalSetData("WorkContext", _workContext); + CallContext.LogicalSetData("WorkContext", new ObjectHandle(_workContext)); CallContext.LogicalSetData("HttpContext", null); var httpContext = lifetimeScope.Resolve(); - CallContext.LogicalSetData("HttpContext", httpContext); + CallContext.LogicalSetData("HttpContext", new ObjectHandle(httpContext)); _disposer = () => { events.Invoke(e => e.Finished(), NullLogger.Instance); From 9593155cb6eeed049c96d1eb633695bfd727d336 Mon Sep 17 00:00:00 2001 From: jtkech Date: Tue, 8 Dec 2015 20:56:20 +0100 Subject: [PATCH 09/15] Update HttpContextAccessor.cs --- src/Orchard/Mvc/HttpContextAccessor.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Orchard/Mvc/HttpContextAccessor.cs b/src/Orchard/Mvc/HttpContextAccessor.cs index f2e35cbab..bb1904df1 100644 --- a/src/Orchard/Mvc/HttpContextAccessor.cs +++ b/src/Orchard/Mvc/HttpContextAccessor.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.Remoting; using System.Runtime.Remoting.Messaging; using System.Web; @@ -9,8 +10,15 @@ namespace Orchard.Mvc { public HttpContextBase Current() { var httpContext = GetStaticProperty(); - return !IsBackgroundHttpContext(httpContext) ? new HttpContextWrapper(httpContext) : - _httpContext ?? CallContext.LogicalGetData("HttpContext") as HttpContextBase; + + if (!IsBackgroundHttpContext(httpContext)) + return new HttpContextWrapper(httpContext); + + if (_httpContext != null) + return _httpContext; + + var context = CallContext.LogicalGetData("HttpContext") as ObjectHandle; + return context != null ? context.Unwrap() as HttpContextBase : null; } public void Set(HttpContextBase httpContext) { From a7b4d8c6ca80761672113befe9c8ad48e1009449 Mon Sep 17 00:00:00 2001 From: jtkech Date: Fri, 11 Dec 2015 01:31:00 +0100 Subject: [PATCH 10/15] Update WorkContextAccessor.cs --- .../Environment/WorkContextAccessor.cs | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/Orchard/Environment/WorkContextAccessor.cs b/src/Orchard/Environment/WorkContextAccessor.cs index e9f2fc4db..72380690c 100644 --- a/src/Orchard/Environment/WorkContextAccessor.cs +++ b/src/Orchard/Environment/WorkContextAccessor.cs @@ -16,19 +16,21 @@ namespace Orchard.Environment { // a different symbolic key is used for each tenant. // this guarantees the correct accessor is being resolved. readonly object _workContextKey = new object(); + private readonly string _workContextSlot; public WorkContextAccessor( IHttpContextAccessor httpContextAccessor, ILifetimeScope lifetimeScope) { _httpContextAccessor = httpContextAccessor; _lifetimeScope = lifetimeScope; + _workContextSlot = "WorkContext." + Guid.NewGuid().ToString("n"); } public WorkContext GetContext(HttpContextBase httpContext) { if (!httpContext.IsBackgroundContext()) return httpContext.Items[_workContextKey] as WorkContext; - var context = CallContext.LogicalGetData("WorkContext") as ObjectHandle; + var context = CallContext.LogicalGetData(_workContextSlot) as ObjectHandle; return context != null ? context.Unwrap() as WorkContext : null; } @@ -37,7 +39,7 @@ namespace Orchard.Environment { if (!httpContext.IsBackgroundContext()) return GetContext(httpContext); - var context = CallContext.LogicalGetData("WorkContext") as ObjectHandle; + var context = CallContext.LogicalGetData(_workContextSlot) as ObjectHandle; return context != null ? context.Unwrap() as WorkContext : null; } @@ -65,7 +67,7 @@ namespace Orchard.Environment { var events = workLifetime.Resolve>(); events.Invoke(e => e.Started(), NullLogger.Instance); - return new CallContextScopeImplementation(events, workLifetime); + return new CallContextScopeImplementation(events, workLifetime, _workContextSlot); } class HttpContextScopeImplementation : IWorkContextScope { @@ -105,18 +107,19 @@ namespace Orchard.Environment { readonly WorkContext _workContext; readonly Action _disposer; - public CallContextScopeImplementation(IEnumerable events, ILifetimeScope lifetimeScope) { - _workContext = lifetimeScope.Resolve(); - CallContext.LogicalSetData("WorkContext", new ObjectHandle(_workContext)); + public CallContextScopeImplementation(IEnumerable events, ILifetimeScope lifetimeScope, string workContextSlot) { - CallContext.LogicalSetData("HttpContext", null); + CallContext.LogicalSetData(workContextSlot, null); + + _workContext = lifetimeScope.Resolve(); var httpContext = lifetimeScope.Resolve(); - CallContext.LogicalSetData("HttpContext", new ObjectHandle(httpContext)); + _workContext.HttpContext = httpContext; + + CallContext.LogicalSetData(workContextSlot, new ObjectHandle(_workContext)); _disposer = () => { events.Invoke(e => e.Finished(), NullLogger.Instance); - CallContext.FreeNamedDataSlot("WorkContext"); - CallContext.FreeNamedDataSlot("HttpContext"); + CallContext.FreeNamedDataSlot(workContextSlot); lifetimeScope.Dispose(); }; } From d34eba4b99109c6db010c5799a730a1e986f6b65 Mon Sep 17 00:00:00 2001 From: jtkech Date: Fri, 11 Dec 2015 01:33:19 +0100 Subject: [PATCH 11/15] Update HttpContextAccessor.cs --- src/Orchard/Mvc/HttpContextAccessor.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Orchard/Mvc/HttpContextAccessor.cs b/src/Orchard/Mvc/HttpContextAccessor.cs index bb1904df1..826bec0ce 100644 --- a/src/Orchard/Mvc/HttpContextAccessor.cs +++ b/src/Orchard/Mvc/HttpContextAccessor.cs @@ -1,13 +1,16 @@ using System; -using System.Runtime.Remoting; -using System.Runtime.Remoting.Messaging; using System.Web; +using Autofac; namespace Orchard.Mvc { - public class HttpContextAccessor : IHttpContextAccessor { + readonly ILifetimeScope _lifetimeScope; private HttpContextBase _httpContext; + public HttpContextAccessor(ILifetimeScope lifetimeScope) { + _lifetimeScope = lifetimeScope; + } + public HttpContextBase Current() { var httpContext = GetStaticProperty(); @@ -17,8 +20,10 @@ namespace Orchard.Mvc { if (_httpContext != null) return _httpContext; - var context = CallContext.LogicalGetData("HttpContext") as ObjectHandle; - return context != null ? context.Unwrap() as HttpContextBase : null; + var workContext = _lifetimeScope.IsRegistered() ? + _lifetimeScope.Resolve().GetContext(null) : null; + + return workContext != null ? workContext.HttpContext : null; } public void Set(HttpContextBase httpContext) { From 095a22eb6eb5b9ef2f31db01832e3c866db58e36 Mon Sep 17 00:00:00 2001 From: jtkech Date: Fri, 11 Dec 2015 01:37:58 +0100 Subject: [PATCH 12/15] Update DefaultWorkContextAccessorTests.cs --- src/Orchard.Tests/Environment/DefaultWorkContextAccessorTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Orchard.Tests/Environment/DefaultWorkContextAccessorTests.cs b/src/Orchard.Tests/Environment/DefaultWorkContextAccessorTests.cs index 27ab4873b..6725f4bd2 100644 --- a/src/Orchard.Tests/Environment/DefaultWorkContextAccessorTests.cs +++ b/src/Orchard.Tests/Environment/DefaultWorkContextAccessorTests.cs @@ -19,6 +19,7 @@ namespace Orchard.Tests.Environment { } protected override void Register(ContainerBuilder builder) { + builder.RegisterModule(new MvcModule()); builder.RegisterModule(new WorkContextModule()); builder.RegisterType().As(); builder.RegisterAutoMocking(); From e889288687495e216a4781efda561ac826454371 Mon Sep 17 00:00:00 2001 From: jtkech Date: Fri, 11 Dec 2015 01:39:35 +0100 Subject: [PATCH 13/15] Update DefaultShellContextFactoryTests.cs --- .../ShellBuilders/DefaultShellContextFactoryTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Orchard.Tests/Environment/ShellBuilders/DefaultShellContextFactoryTests.cs b/src/Orchard.Tests/Environment/ShellBuilders/DefaultShellContextFactoryTests.cs index dc0b13a26..73d55e661 100644 --- a/src/Orchard.Tests/Environment/ShellBuilders/DefaultShellContextFactoryTests.cs +++ b/src/Orchard.Tests/Environment/ShellBuilders/DefaultShellContextFactoryTests.cs @@ -21,6 +21,7 @@ namespace Orchard.Tests.Environment.ShellBuilders { public void Init() { var builder = new ContainerBuilder(); builder.RegisterType().As(); + builder.RegisterModule(new MvcModule()); builder.RegisterModule(new WorkContextModule()); builder.RegisterType().As(); builder.RegisterAutoMocking(Moq.MockBehavior.Strict); @@ -93,4 +94,4 @@ namespace Orchard.Tests.Environment.ShellBuilders { Assert.That(context.Descriptor.Features, Has.Some.With.Property("Name").EqualTo("Orchard.Setup")); } } -} \ No newline at end of file +} From e72b8c4bed4eaec229aab7336cdb2df19f00eb35 Mon Sep 17 00:00:00 2001 From: jtkech Date: Fri, 11 Dec 2015 01:40:35 +0100 Subject: [PATCH 14/15] Update SweepGeneratorTests.cs --- src/Orchard.Tests/Tasks/SweepGeneratorTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Orchard.Tests/Tasks/SweepGeneratorTests.cs b/src/Orchard.Tests/Tasks/SweepGeneratorTests.cs index 8e468800a..7f6cf6874 100644 --- a/src/Orchard.Tests/Tasks/SweepGeneratorTests.cs +++ b/src/Orchard.Tests/Tasks/SweepGeneratorTests.cs @@ -13,6 +13,7 @@ namespace Orchard.Tests.Tasks { public class SweepGeneratorTests : ContainerTestBase { protected override void Register(ContainerBuilder builder) { builder.RegisterAutoMocking(MockBehavior.Loose); + builder.RegisterModule(new MvcModule()); builder.RegisterModule(new WorkContextModule()); builder.RegisterType().As(); builder.RegisterType(); From 981c1cb0562204e085234e5b955dc7ad3d5cb64d Mon Sep 17 00:00:00 2001 From: jtkech Date: Thu, 17 Dec 2015 07:08:12 +0100 Subject: [PATCH 15/15] Update HttpContextAccessor.cs --- src/Orchard/Mvc/HttpContextAccessor.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Orchard/Mvc/HttpContextAccessor.cs b/src/Orchard/Mvc/HttpContextAccessor.cs index 826bec0ce..0c5e3438a 100644 --- a/src/Orchard/Mvc/HttpContextAccessor.cs +++ b/src/Orchard/Mvc/HttpContextAccessor.cs @@ -6,6 +6,7 @@ namespace Orchard.Mvc { public class HttpContextAccessor : IHttpContextAccessor { readonly ILifetimeScope _lifetimeScope; private HttpContextBase _httpContext; + private IWorkContextAccessor _wca; public HttpContextAccessor(ILifetimeScope lifetimeScope) { _lifetimeScope = lifetimeScope; @@ -20,9 +21,10 @@ namespace Orchard.Mvc { if (_httpContext != null) return _httpContext; - var workContext = _lifetimeScope.IsRegistered() ? - _lifetimeScope.Resolve().GetContext(null) : null; + if (_wca == null && _lifetimeScope.IsRegistered()) + _wca = _lifetimeScope.Resolve(); + var workContext = _wca != null ? _wca.GetContext(null) : null; return workContext != null ? workContext.HttpContext : null; }