mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 11:44:58 +08:00
Merge pull request #5966 from jtkech/patch-2
Experimental work on HttpContext, WorkContext and async code in background tasks
This commit is contained in:
@@ -19,6 +19,7 @@ namespace Orchard.Tests.Environment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override void Register(ContainerBuilder builder) {
|
protected override void Register(ContainerBuilder builder) {
|
||||||
|
builder.RegisterModule(new MvcModule());
|
||||||
builder.RegisterModule(new WorkContextModule());
|
builder.RegisterModule(new WorkContextModule());
|
||||||
builder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>();
|
builder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>();
|
||||||
builder.RegisterAutoMocking();
|
builder.RegisterAutoMocking();
|
||||||
|
@@ -21,6 +21,7 @@ namespace Orchard.Tests.Environment.ShellBuilders {
|
|||||||
public void Init() {
|
public void Init() {
|
||||||
var builder = new ContainerBuilder();
|
var builder = new ContainerBuilder();
|
||||||
builder.RegisterType<ShellContextFactory>().As<IShellContextFactory>();
|
builder.RegisterType<ShellContextFactory>().As<IShellContextFactory>();
|
||||||
|
builder.RegisterModule(new MvcModule());
|
||||||
builder.RegisterModule(new WorkContextModule());
|
builder.RegisterModule(new WorkContextModule());
|
||||||
builder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>();
|
builder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>();
|
||||||
builder.RegisterAutoMocking(Moq.MockBehavior.Strict);
|
builder.RegisterAutoMocking(Moq.MockBehavior.Strict);
|
||||||
|
@@ -13,6 +13,7 @@ namespace Orchard.Tests.Tasks {
|
|||||||
public class SweepGeneratorTests : ContainerTestBase {
|
public class SweepGeneratorTests : ContainerTestBase {
|
||||||
protected override void Register(ContainerBuilder builder) {
|
protected override void Register(ContainerBuilder builder) {
|
||||||
builder.RegisterAutoMocking(MockBehavior.Loose);
|
builder.RegisterAutoMocking(MockBehavior.Loose);
|
||||||
|
builder.RegisterModule(new MvcModule());
|
||||||
builder.RegisterModule(new WorkContextModule());
|
builder.RegisterModule(new WorkContextModule());
|
||||||
builder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>();
|
builder.RegisterType<WorkContextAccessor>().As<IWorkContextAccessor>();
|
||||||
builder.RegisterType<SweepGenerator>();
|
builder.RegisterType<SweepGenerator>();
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.Remoting;
|
||||||
|
using System.Runtime.Remoting.Messaging;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using Autofac;
|
using Autofac;
|
||||||
using Orchard.Logging;
|
using Orchard.Logging;
|
||||||
@@ -15,23 +16,22 @@ namespace Orchard.Environment {
|
|||||||
// a different symbolic key is used for each tenant.
|
// a different symbolic key is used for each tenant.
|
||||||
// this guarantees the correct accessor is being resolved.
|
// this guarantees the correct accessor is being resolved.
|
||||||
readonly object _workContextKey = new object();
|
readonly object _workContextKey = new object();
|
||||||
|
private readonly string _workContextSlot;
|
||||||
[ThreadStatic]
|
|
||||||
static ConcurrentDictionary<object, WorkContext> _threadStaticContexts;
|
|
||||||
|
|
||||||
public WorkContextAccessor(
|
public WorkContextAccessor(
|
||||||
IHttpContextAccessor httpContextAccessor,
|
IHttpContextAccessor httpContextAccessor,
|
||||||
ILifetimeScope lifetimeScope) {
|
ILifetimeScope lifetimeScope) {
|
||||||
_httpContextAccessor = httpContextAccessor;
|
_httpContextAccessor = httpContextAccessor;
|
||||||
_lifetimeScope = lifetimeScope;
|
_lifetimeScope = lifetimeScope;
|
||||||
|
_workContextSlot = "WorkContext." + Guid.NewGuid().ToString("n");
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorkContext GetContext(HttpContextBase httpContext) {
|
public WorkContext GetContext(HttpContextBase httpContext) {
|
||||||
if (!httpContext.IsBackgroundContext())
|
if (!httpContext.IsBackgroundContext())
|
||||||
return httpContext.Items[_workContextKey] as WorkContext;
|
return httpContext.Items[_workContextKey] as WorkContext;
|
||||||
|
|
||||||
WorkContext workContext;
|
var context = CallContext.LogicalGetData(_workContextSlot) as ObjectHandle;
|
||||||
return EnsureThreadStaticContexts().TryGetValue(_workContextKey, out workContext) ? workContext : null;
|
return context != null ? context.Unwrap() as WorkContext : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorkContext GetContext() {
|
public WorkContext GetContext() {
|
||||||
@@ -39,8 +39,8 @@ namespace Orchard.Environment {
|
|||||||
if (!httpContext.IsBackgroundContext())
|
if (!httpContext.IsBackgroundContext())
|
||||||
return GetContext(httpContext);
|
return GetContext(httpContext);
|
||||||
|
|
||||||
WorkContext workContext;
|
var context = CallContext.LogicalGetData(_workContextSlot) as ObjectHandle;
|
||||||
return EnsureThreadStaticContexts().TryGetValue(_workContextKey, out workContext) ? workContext : null;
|
return context != null ? context.Unwrap() as WorkContext : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IWorkContextScope CreateWorkContextScope(HttpContextBase httpContext) {
|
public IWorkContextScope CreateWorkContextScope(HttpContextBase httpContext) {
|
||||||
@@ -57,7 +57,6 @@ namespace Orchard.Environment {
|
|||||||
_workContextKey);
|
_workContextKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public IWorkContextScope CreateWorkContextScope() {
|
public IWorkContextScope CreateWorkContextScope() {
|
||||||
var httpContext = _httpContextAccessor.Current();
|
var httpContext = _httpContextAccessor.Current();
|
||||||
if (!httpContext.IsBackgroundContext())
|
if (!httpContext.IsBackgroundContext())
|
||||||
@@ -68,18 +67,9 @@ namespace Orchard.Environment {
|
|||||||
var events = workLifetime.Resolve<IEnumerable<IWorkContextEvents>>();
|
var events = workLifetime.Resolve<IEnumerable<IWorkContextEvents>>();
|
||||||
events.Invoke(e => e.Started(), NullLogger.Instance);
|
events.Invoke(e => e.Started(), NullLogger.Instance);
|
||||||
|
|
||||||
return new ThreadStaticScopeImplementation(
|
return new CallContextScopeImplementation(events, workLifetime, _workContextSlot);
|
||||||
events,
|
|
||||||
workLifetime,
|
|
||||||
EnsureThreadStaticContexts(),
|
|
||||||
_workContextKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConcurrentDictionary<object, WorkContext> EnsureThreadStaticContexts() {
|
|
||||||
return _threadStaticContexts ?? (_threadStaticContexts = new ConcurrentDictionary<object, WorkContext>());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class HttpContextScopeImplementation : IWorkContextScope {
|
class HttpContextScopeImplementation : IWorkContextScope {
|
||||||
readonly WorkContext _workContext;
|
readonly WorkContext _workContext;
|
||||||
readonly Action _disposer;
|
readonly Action _disposer;
|
||||||
@@ -113,19 +103,23 @@ namespace Orchard.Environment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ThreadStaticScopeImplementation : IWorkContextScope {
|
class CallContextScopeImplementation : IWorkContextScope {
|
||||||
readonly WorkContext _workContext;
|
readonly WorkContext _workContext;
|
||||||
readonly Action _disposer;
|
readonly Action _disposer;
|
||||||
|
|
||||||
public ThreadStaticScopeImplementation(IEnumerable<IWorkContextEvents> events, ILifetimeScope lifetimeScope, ConcurrentDictionary<object, WorkContext> contexts, object workContextKey) {
|
public CallContextScopeImplementation(IEnumerable<IWorkContextEvents> events, ILifetimeScope lifetimeScope, string workContextSlot) {
|
||||||
|
|
||||||
|
CallContext.LogicalSetData(workContextSlot, null);
|
||||||
|
|
||||||
_workContext = lifetimeScope.Resolve<WorkContext>();
|
_workContext = lifetimeScope.Resolve<WorkContext>();
|
||||||
contexts.AddOrUpdate(workContextKey, _workContext, (a, b) => _workContext);
|
var httpContext = lifetimeScope.Resolve<HttpContextBase>();
|
||||||
|
_workContext.HttpContext = httpContext;
|
||||||
|
|
||||||
|
CallContext.LogicalSetData(workContextSlot, new ObjectHandle(_workContext));
|
||||||
|
|
||||||
_disposer = () => {
|
_disposer = () => {
|
||||||
events.Invoke(e => e.Finished(), NullLogger.Instance);
|
events.Invoke(e => e.Finished(), NullLogger.Instance);
|
||||||
|
CallContext.FreeNamedDataSlot(workContextSlot);
|
||||||
WorkContext removedContext;
|
|
||||||
contexts.TryRemove(workContextKey, out removedContext);
|
|
||||||
lifetimeScope.Dispose();
|
lifetimeScope.Dispose();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using System.Web;
|
using System.Web;
|
||||||
|
|
||||||
namespace Orchard.Mvc.Extensions {
|
namespace Orchard.Mvc.Extensions {
|
||||||
public static class HttpContextBaseExtensions {
|
public static class HttpContextBaseExtensions {
|
||||||
|
@@ -1,13 +1,31 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
|
using Autofac;
|
||||||
|
|
||||||
namespace Orchard.Mvc {
|
namespace Orchard.Mvc {
|
||||||
public class HttpContextAccessor : IHttpContextAccessor {
|
public class HttpContextAccessor : IHttpContextAccessor {
|
||||||
|
readonly ILifetimeScope _lifetimeScope;
|
||||||
private HttpContextBase _httpContext;
|
private HttpContextBase _httpContext;
|
||||||
|
private IWorkContextAccessor _wca;
|
||||||
|
|
||||||
|
public HttpContextAccessor(ILifetimeScope lifetimeScope) {
|
||||||
|
_lifetimeScope = lifetimeScope;
|
||||||
|
}
|
||||||
|
|
||||||
public HttpContextBase Current() {
|
public HttpContextBase Current() {
|
||||||
var httpContext = GetStaticProperty();
|
var httpContext = GetStaticProperty();
|
||||||
return !IsBackgroundHttpContext(httpContext) ? new HttpContextWrapper(httpContext) : _httpContext;
|
|
||||||
|
if (!IsBackgroundHttpContext(httpContext))
|
||||||
|
return new HttpContextWrapper(httpContext);
|
||||||
|
|
||||||
|
if (_httpContext != null)
|
||||||
|
return _httpContext;
|
||||||
|
|
||||||
|
if (_wca == null && _lifetimeScope.IsRegistered<IWorkContextAccessor>())
|
||||||
|
_wca = _lifetimeScope.Resolve<IWorkContextAccessor>();
|
||||||
|
|
||||||
|
var workContext = _wca != null ? _wca.GetContext(null) : null;
|
||||||
|
return workContext != null ? workContext.HttpContext : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Set(HttpContextBase httpContext) {
|
public void Set(HttpContextBase httpContext) {
|
||||||
@@ -15,7 +33,7 @@ namespace Orchard.Mvc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsBackgroundHttpContext(HttpContext httpContext) {
|
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() {
|
private static HttpContext GetStaticProperty() {
|
||||||
|
@@ -3,18 +3,20 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using System.Web.Caching;
|
using System.Web.Caching;
|
||||||
using System.Web.Instrumentation;
|
using System.Web.Instrumentation;
|
||||||
using System.Web.Mvc;
|
using System.Web.Mvc;
|
||||||
using System.Web.Routing;
|
using System.Web.Routing;
|
||||||
using Autofac;
|
using Autofac;
|
||||||
|
using Orchard.Mvc.Extensions;
|
||||||
using Orchard.Mvc.Routes;
|
using Orchard.Mvc.Routes;
|
||||||
using Orchard.Settings;
|
using Orchard.Settings;
|
||||||
using Orchard.Exceptions;
|
|
||||||
|
|
||||||
namespace Orchard.Mvc {
|
namespace Orchard.Mvc {
|
||||||
public class MvcModule : Module {
|
public class MvcModule : Module {
|
||||||
|
public const string IsBackgroundHttpContextKey = "IsBackgroundHttpContext";
|
||||||
|
|
||||||
protected override void Load(ContainerBuilder moduleBuilder) {
|
protected override void Load(ContainerBuilder moduleBuilder) {
|
||||||
moduleBuilder.RegisterType<ShellRoute>().InstancePerDependency();
|
moduleBuilder.RegisterType<ShellRoute>().InstancePerDependency();
|
||||||
@@ -24,29 +26,11 @@ namespace Orchard.Mvc {
|
|||||||
moduleBuilder.Register(UrlHelperFactory).As<UrlHelper>().InstancePerDependency();
|
moduleBuilder.Register(UrlHelperFactory).As<UrlHelper>().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) {
|
static HttpContextBase HttpContextBaseFactory(IComponentContext context) {
|
||||||
if (IsRequestValid()) {
|
|
||||||
return new HttpContextWrapper(HttpContext.Current);
|
var httpContext = context.Resolve<IHttpContextAccessor>().Current();
|
||||||
}
|
if (httpContext != null)
|
||||||
|
return httpContext;
|
||||||
|
|
||||||
var siteService = context.Resolve<ISiteService>();
|
var siteService = context.Resolve<ISiteService>();
|
||||||
|
|
||||||
@@ -54,17 +38,18 @@ namespace Orchard.Mvc {
|
|||||||
// so that the RequestContext will have been established when the time comes to actually load the site settings,
|
// 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,
|
// which requires activating the Site content item, which in turn requires a UrlHelper, which in turn requires a RequestContext,
|
||||||
// thus preventing a StackOverflowException.
|
// thus preventing a StackOverflowException.
|
||||||
|
|
||||||
var baseUrl = new Func<string>(() => siteService.GetSiteSettings().BaseUrl);
|
var baseUrl = new Func<string>(() => siteService.GetSiteSettings().BaseUrl);
|
||||||
var httpContextBase = new HttpContextPlaceholder(baseUrl);
|
var httpContextBase = new HttpContextPlaceholder(baseUrl);
|
||||||
|
|
||||||
context.Resolve<IWorkContextAccessor>().CreateWorkContextScope(httpContextBase);
|
|
||||||
return httpContextBase;
|
return httpContextBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RequestContext RequestContextFactory(IComponentContext context) {
|
static RequestContext RequestContextFactory(IComponentContext context) {
|
||||||
var httpContextAccessor = context.Resolve<IHttpContextAccessor>();
|
|
||||||
var httpContext = httpContextAccessor.Current();
|
var httpContext = HttpContextBaseFactory(context);
|
||||||
if (httpContext != null) {
|
|
||||||
|
if (!httpContext.IsBackgroundContext()) {
|
||||||
|
|
||||||
var mvcHandler = httpContext.Handler as MvcHandler;
|
var mvcHandler = httpContext.Handler as MvcHandler;
|
||||||
if (mvcHandler != null) {
|
if (mvcHandler != null) {
|
||||||
@@ -77,8 +62,8 @@ namespace Orchard.Mvc {
|
|||||||
return hasRequestContext.RequestContext;
|
return hasRequestContext.RequestContext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else if (httpContext is HttpContextPlaceholder) {
|
||||||
httpContext = HttpContextBaseFactory(context);
|
return ((HttpContextPlaceholder)httpContext).RequestContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RequestContext(httpContext, new RouteData());
|
return new RequestContext(httpContext, new RouteData());
|
||||||
@@ -91,7 +76,9 @@ namespace Orchard.Mvc {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Standin context for background tasks.
|
/// Standin context for background tasks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class HttpContextPlaceholder : HttpContextBase {
|
public class HttpContextPlaceholder : HttpContextBase, IDisposable {
|
||||||
|
private HttpContext _httpContext;
|
||||||
|
private HttpRequestPlaceholder _request;
|
||||||
private readonly Lazy<string> _baseUrl;
|
private readonly Lazy<string> _baseUrl;
|
||||||
private readonly IDictionary _items = new Dictionary<object, object>();
|
private readonly IDictionary _items = new Dictionary<object, object>();
|
||||||
|
|
||||||
@@ -99,8 +86,54 @@ namespace Orchard.Mvc {
|
|||||||
_baseUrl = new Lazy<string>(baseUrl);
|
_baseUrl = new Lazy<string>(baseUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
_httpContext = null;
|
||||||
|
if (HttpContext.Current != null)
|
||||||
|
HttpContext.Current = null;
|
||||||
|
}
|
||||||
|
|
||||||
public override HttpRequestBase Request {
|
public override HttpRequestBase Request {
|
||||||
get { return new HttpRequestPlaceholder(new Uri(_baseUrl.Value)); }
|
|
||||||
|
// 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;
|
||||||
|
_httpContext = httpContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HttpContext.Current != _httpContext)
|
||||||
|
HttpContext.Current = _httpContext;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override HttpSessionStateBase Session {
|
||||||
|
get { return new HttpSessionStatePlaceholder(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IHttpHandler Handler { get; set; }
|
public override IHttpHandler Handler { get; set; }
|
||||||
@@ -130,6 +163,14 @@ namespace Orchard.Mvc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class HttpSessionStatePlaceholder : HttpSessionStateBase {
|
||||||
|
public override object this[string name] {
|
||||||
|
get {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class HttpResponsePlaceholder : HttpResponseBase {
|
public class HttpResponsePlaceholder : HttpResponseBase {
|
||||||
public override string ApplyAppPathModifier(string virtualPath) {
|
public override string ApplyAppPathModifier(string virtualPath) {
|
||||||
return virtualPath;
|
return virtualPath;
|
||||||
@@ -146,10 +187,36 @@ namespace Orchard.Mvc {
|
|||||||
/// standin context for background tasks.
|
/// standin context for background tasks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class HttpRequestPlaceholder : HttpRequestBase {
|
public class HttpRequestPlaceholder : HttpRequestBase {
|
||||||
private readonly Uri _uri;
|
private HttpContextBase _httpContext;
|
||||||
|
private RequestContext _requestContext;
|
||||||
|
private readonly Lazy<string> _baseUrl;
|
||||||
|
private readonly NameValueCollection _queryString = new NameValueCollection();
|
||||||
|
private Uri _uri;
|
||||||
|
|
||||||
public HttpRequestPlaceholder(Uri uri) {
|
public HttpRequestPlaceholder(HttpContextBase httpContext, Lazy<string> baseUrl) {
|
||||||
_uri = uri;
|
_httpContext = httpContext;
|
||||||
|
_baseUrl = baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override RequestContext RequestContext {
|
||||||
|
get {
|
||||||
|
if (_requestContext == null) {
|
||||||
|
_requestContext = new RequestContext(_httpContext, new RouteData());
|
||||||
|
}
|
||||||
|
return _requestContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override NameValueCollection QueryString {
|
||||||
|
get {
|
||||||
|
return _queryString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string RawUrl {
|
||||||
|
get {
|
||||||
|
return Url.OriginalString;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -179,13 +246,16 @@ namespace Orchard.Mvc {
|
|||||||
|
|
||||||
public override Uri Url {
|
public override Uri Url {
|
||||||
get {
|
get {
|
||||||
|
if (_uri == null) {
|
||||||
|
_uri = new Uri(_baseUrl.Value);
|
||||||
|
}
|
||||||
return _uri;
|
return _uri;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override NameValueCollection Headers {
|
public override NameValueCollection Headers {
|
||||||
get {
|
get {
|
||||||
return new NameValueCollection { { "Host", _uri.Authority } };
|
return new NameValueCollection { { "Host", Url.Authority } };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,15 +279,15 @@ namespace Orchard.Mvc {
|
|||||||
|
|
||||||
public override string ApplicationPath {
|
public override string ApplicationPath {
|
||||||
get {
|
get {
|
||||||
return _uri.LocalPath;
|
return Url.LocalPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override NameValueCollection ServerVariables {
|
public override NameValueCollection ServerVariables {
|
||||||
get {
|
get {
|
||||||
return new NameValueCollection {
|
return new NameValueCollection {
|
||||||
{ "SERVER_PORT", _uri.Port.ToString(CultureInfo.InvariantCulture) },
|
{ "SERVER_PORT", Url.Port.ToString(CultureInfo.InvariantCulture) },
|
||||||
{ "HTTP_HOST", _uri.Authority.ToString(CultureInfo.InvariantCulture) },
|
{ "HTTP_HOST", Url.Authority.ToString(CultureInfo.InvariantCulture) },
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user