diff --git a/src/Orchard/BackgroundHttpContext.cs b/src/Orchard/BackgroundHttpContext.cs
new file mode 100644
index 000000000..1b4f68f3b
--- /dev/null
+++ b/src/Orchard/BackgroundHttpContext.cs
@@ -0,0 +1,38 @@
+using System.IO;
+using System.Web;
+using Orchard.Settings;
+
+namespace Orchard {
+ ///
+ /// A factory class that creates an HttpContext instance and initializes the HttpContext.Current property with that instance.
+ /// This is useful when rendering views from a background thread, as some Html Helpers access HttpContext.Current directly, thus preventing a NullReferenceException.
+ ///
+ public class BackgroundHttpContextFactory : IBackgroundHttpContextFactory {
+ public const string IsBackgroundHttpContextKey = "IsBackgroundHttpContext";
+ private readonly ISiteService _siteService;
+ public BackgroundHttpContextFactory(ISiteService siteService) {
+ _siteService = siteService;
+ }
+
+ public HttpContext CreateHttpContext() {
+ var url = _siteService.GetSiteSettings().BaseUrl;
+ var httpContext = new HttpContext(new HttpRequest("", url, ""), new HttpResponse(new StringWriter()));
+
+ httpContext.Items[IsBackgroundHttpContextKey] = true;
+
+ return httpContext;
+ }
+
+ public void InitializeHttpContext() {
+ if (HttpContext.Current != null)
+ return;
+
+ HttpContext.Current = CreateHttpContext();
+ }
+ }
+
+ public interface IBackgroundHttpContextFactory : IDependency {
+ HttpContext CreateHttpContext();
+ void InitializeHttpContext();
+ }
+}
diff --git a/src/Orchard/Mvc/HttpContextAccessor.cs b/src/Orchard/Mvc/HttpContextAccessor.cs
new file mode 100644
index 000000000..615d527df
--- /dev/null
+++ b/src/Orchard/Mvc/HttpContextAccessor.cs
@@ -0,0 +1,39 @@
+using System;
+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;
+ }
+
+ public void Set(HttpContextBase httpContext) {
+ _httpContext = httpContext;
+ }
+
+ private static bool IsBackgroundHttpContext(HttpContext httpContext) {
+ return httpContext == null || httpContext.Items.Contains(BackgroundHttpContextFactory.IsBackgroundHttpContextKey);
+ }
+
+ private static HttpContext GetStaticProperty() {
+ var httpContext = HttpContext.Current;
+ if (httpContext == null) {
+ return null;
+ }
+
+ try {
+ // The "Request" property throws at application startup on IIS integrated pipeline mode.
+ if (httpContext.Request == null) {
+ return null;
+ }
+ }
+ catch (Exception) {
+ return null;
+ }
+ return httpContext;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Orchard/Mvc/IHttpContextAccessor.cs b/src/Orchard/Mvc/IHttpContextAccessor.cs
index 91208d314..462887fee 100644
--- a/src/Orchard/Mvc/IHttpContextAccessor.cs
+++ b/src/Orchard/Mvc/IHttpContextAccessor.cs
@@ -1,39 +1,8 @@
-using System;
-using System.Web;
+using System.Web;
namespace Orchard.Mvc {
public interface IHttpContextAccessor {
HttpContextBase Current();
void Set(HttpContextBase httpContext);
}
-
- public class HttpContextAccessor : IHttpContextAccessor {
- private HttpContextBase _httpContext;
-
- public HttpContextBase Current() {
- var httpContext = GetStaticProperty();
- return httpContext != null ? new HttpContextWrapper(httpContext) : _httpContext;
- }
-
- public void Set(HttpContextBase httpContext) {
- _httpContext = httpContext;
- }
-
- private HttpContext GetStaticProperty() {
- var httpContext = HttpContext.Current;
- if (httpContext == null) {
- return null;
- }
-
- try {
- if (httpContext.Request == null) {
- return null;
- }
- }
- catch (Exception) {
- return null;
- }
- return httpContext;
- }
- }
}
diff --git a/src/Orchard/Mvc/MvcModule.cs b/src/Orchard/Mvc/MvcModule.cs
index 1e0c49ce6..e1e8c19eb 100644
--- a/src/Orchard/Mvc/MvcModule.cs
+++ b/src/Orchard/Mvc/MvcModule.cs
@@ -28,7 +28,7 @@ namespace Orchard.Mvc {
return false;
try {
- // The "Request" property throws at application startup on IIS integrated pipeline mode
+ // The "Request" property throws at application startup on IIS integrated pipeline mode.
var req = HttpContext.Current.Request;
}
catch (Exception) {
diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj
index a7093e72b..65099a4cc 100644
--- a/src/Orchard/Orchard.Framework.csproj
+++ b/src/Orchard/Orchard.Framework.csproj
@@ -317,6 +317,7 @@
+
@@ -644,6 +645,7 @@
+
diff --git a/src/Orchard/Tasks/BackgroundService.cs b/src/Orchard/Tasks/BackgroundService.cs
index 8956595bd..b952a6a26 100644
--- a/src/Orchard/Tasks/BackgroundService.cs
+++ b/src/Orchard/Tasks/BackgroundService.cs
@@ -16,24 +16,28 @@ namespace Orchard.Tasks {
public class BackgroundService : IBackgroundService {
private readonly IEnumerable _tasks;
private readonly ITransactionManager _transactionManager;
+ private readonly IBackgroundHttpContextFactory _backgroundHttpContextFactory;
private readonly string _shellName;
- private readonly IContentManager _contentManager;
public BackgroundService(
IEnumerable tasks,
ITransactionManager transactionManager,
ShellSettings shellSettings,
- IContentManager contentManager) {
+ IContentManager contentManager,
+ IBackgroundHttpContextFactory backgroundHttpContextFactory) {
+
_tasks = tasks;
_transactionManager = transactionManager;
+ _backgroundHttpContextFactory = backgroundHttpContextFactory;
_shellName = shellSettings.Name;
- _contentManager = contentManager;
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
public void Sweep() {
+ _backgroundHttpContextFactory.InitializeHttpContext();
+
foreach(var task in _tasks) {
var taskName = task.GetType().FullName;