Started replacing UmbracoContext.HttpContext with injection of IHttpContextAccessor

This commit is contained in:
Bjarke Berg
2020-02-10 13:09:26 +01:00
parent aa6a70efba
commit d151503dbf
25 changed files with 329 additions and 50 deletions
@@ -1,8 +1,10 @@
using NUnit.Framework;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web;
using Umbraco.Web.Routing;
namespace Umbraco.Tests.Routing
@@ -18,7 +20,7 @@ namespace Umbraco.Tests.Routing
var umbracoContext = GetUmbracoContext(urlAsString);
var publishedRouter = CreatePublishedRouter();
var frequest = publishedRouter.CreateRequest(umbracoContext);
var lookup = new ContentFinderByIdPath(Factory.GetInstance<IUmbracoSettingsSection>().WebRouting, Logger);
var lookup = new ContentFinderByIdPath(Factory.GetInstance<IUmbracoSettingsSection>().WebRouting, Logger, HttpContextAccessor);
var result = lookup.TryFindContent(frequest);
@@ -1,6 +1,7 @@
using Moq;
using NUnit.Framework;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web;
using Umbraco.Web.Routing;
namespace Umbraco.Tests.Routing
@@ -16,15 +17,18 @@ namespace Umbraco.Tests.Routing
public void Lookup_By_Page_Id(string urlAsString, int nodeMatch)
{
var umbracoContext = GetUmbracoContext(urlAsString);
var httpContext = GetHttpContextFactory(urlAsString).HttpContext;
var publishedRouter = CreatePublishedRouter();
var frequest = publishedRouter.CreateRequest(umbracoContext);
var lookup = new ContentFinderByPageIdQuery();
var mockHttpContextAccessor = new Mock<IHttpContextAccessor>();
mockHttpContextAccessor.Setup(x => x.HttpContext).Returns(httpContext);
var lookup = new ContentFinderByPageIdQuery(mockHttpContextAccessor.Object);
//we need to manually stub the return output of HttpContext.Request["umbPageId"]
var requestMock = Mock.Get(umbracoContext.HttpContext.Request);
var requestMock = Mock.Get(httpContext.Request);
requestMock.Setup(x => x["umbPageID"])
.Returns(umbracoContext.HttpContext.Request.QueryString["umbPageID"]);
.Returns(httpContext.Request.QueryString["umbPageID"]);
var result = lookup.TryFindContent(frequest);
@@ -100,10 +100,12 @@ namespace Umbraco.Tests.Routing
[Test]
public void Umbraco_Route_Umbraco_Defined_Controller_Action()
{
var url = "~/dummy-page";
var template = CreateTemplate("homePage");
var route = RouteTable.Routes["Umbraco_default"];
var routeData = new RouteData { Route = route };
var umbracoContext = GetUmbracoContext("~/dummy-page", template.Id, routeData);
var umbracoContext = GetUmbracoContext(url, template.Id, routeData);
var httpContext = GetHttpContextFactory(url, routeData).HttpContext;
var publishedRouter = CreatePublishedRouter();
var frequest = publishedRouter.CreateRequest(umbracoContext);
frequest.PublishedContent = umbracoContext.Content.GetById(1174);
@@ -112,7 +114,7 @@ namespace Umbraco.Tests.Routing
var umbracoContextAccessor = new TestUmbracoContextAccessor(umbracoContext);
var handler = new RenderRouteHandler(umbracoContext, new TestControllerFactory(umbracoContextAccessor, Mock.Of<ILogger>()), ShortStringHelper);
handler.GetHandlerForRoute(umbracoContext.HttpContext.Request.RequestContext, frequest);
handler.GetHandlerForRoute(httpContext.Request.RequestContext, frequest);
Assert.AreEqual("RenderMvc", routeData.Values["controller"].ToString());
//the route action will still be the one we've asked for because our RenderActionInvoker is the thing that decides
// if the action matches.
@@ -136,10 +138,12 @@ namespace Umbraco.Tests.Routing
// could exist in the database... yet creating templates should sanitize
// aliases one way or another...
var url = "~/dummy-page";
var template = CreateTemplate(templateName);
var route = RouteTable.Routes["Umbraco_default"];
var routeData = new RouteData() {Route = route};
var umbracoContext = GetUmbracoContext("~/dummy-page", template.Id, routeData, true);
var httpContext = GetHttpContextFactory(url, routeData).HttpContext;
var publishedRouter = CreatePublishedRouter();
var frequest = publishedRouter.CreateRequest(umbracoContext);
frequest.PublishedContent = umbracoContext.Content.GetById(1172);
@@ -152,7 +156,7 @@ namespace Umbraco.Tests.Routing
var handler = new RenderRouteHandler(umbracoContext, new TestControllerFactory(umbracoContextAccessor, Mock.Of<ILogger>(), context =>
{
var membershipHelper = new MembershipHelper(
umbracoContext.HttpContext, Mock.Of<IPublishedMemberCache>(), Mock.Of<MembersMembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IPublicAccessService>(), AppCaches.Disabled, Mock.Of<ILogger>(), ShortStringHelper, Mock.Of<IEntityService>());
httpContext, Mock.Of<IPublishedMemberCache>(), Mock.Of<MembersMembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IPublicAccessService>(), AppCaches.Disabled, Mock.Of<ILogger>(), ShortStringHelper, Mock.Of<IEntityService>());
return new CustomDocumentController(Factory.GetInstance<IGlobalSettings>(),
umbracoContextAccessor,
Factory.GetInstance<ServiceContext>(),
@@ -161,7 +165,7 @@ namespace Umbraco.Tests.Routing
new UmbracoHelper(Mock.Of<IPublishedContent>(), Mock.Of<ITagQuery>(), Mock.Of<ICultureDictionaryFactory>(), Mock.Of<IUmbracoComponentRenderer>(), Mock.Of<IPublishedContentQuery>(), membershipHelper));
}), ShortStringHelper);
handler.GetHandlerForRoute(umbracoContext.HttpContext.Request.RequestContext, frequest);
handler.GetHandlerForRoute(httpContext.Request.RequestContext, frequest);
Assert.AreEqual("CustomDocument", routeData.Values["controller"].ToString());
Assert.AreEqual(
//global::umbraco.cms.helpers.Casing.SafeAlias(template.Alias),
+3 -1
View File
@@ -15,6 +15,7 @@ using Umbraco.Core.Strings;
using Umbraco.Tests.PublishedContent;
using Umbraco.Tests.TestHelpers.Stubs;
using Umbraco.Tests.Testing.Objects.Accessors;
using Umbraco.Web;
using Umbraco.Web.Composing;
using Umbraco.Web.Models.PublishedContent;
using Umbraco.Web.Routing;
@@ -102,7 +103,8 @@ namespace Umbraco.Tests.TestHelpers
container?.TryGetInstance<ServiceContext>() ?? ServiceContext.CreatePartial(),
new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()),
container?.TryGetInstance<IUmbracoSettingsSection>() ?? Current.Factory.GetInstance<IUmbracoSettingsSection>(),
Mock.Of<IUserService>());
Mock.Of<IUserService>(),
Mock.Of<IHttpContextAccessor>());
}
}
}
@@ -337,5 +337,16 @@ namespace Umbraco.Tests.TestHelpers
}
#endregion
public IHttpContextAccessor GetHttpContextAccessor(HttpContextBase httpContextBase = null)
{
var mock = new Mock<IHttpContextAccessor>();
var httpContext = UmbracoContextFactory.EnsureHttpContext(httpContextBase);
mock.Setup(x => x.HttpContext).Returns(httpContext);
return mock.Object;
}
}
}
@@ -31,6 +31,7 @@ using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Tests.LegacyXmlPublishedCache;
using Umbraco.Tests.Testing.Objects.Accessors;
using Umbraco.Web.WebApi;
namespace Umbraco.Tests.TestHelpers
{
@@ -81,6 +82,9 @@ namespace Umbraco.Tests.TestHelpers
.Clear()
.Add(() => Composition.TypeLoader.GetDataEditors());
Composition.WithCollectionBuilder<UmbracoApiControllerTypeCollectionBuilder>()
.Add(Composition.TypeLoader.GetUmbracoApiControllers());
Composition.RegisterUnique(f =>
{
if (Options.Database == UmbracoTestOptions.Database.None)
@@ -5,6 +5,6 @@ namespace Umbraco.Tests.Testing.Objects.Accessors
{
public class NoHttpContextAccessor : IHttpContextAccessor
{
public HttpContext HttpContext { get; set; } = null;
public HttpContextBase HttpContext { get; set; } = null;
}
}
@@ -1,6 +1,7 @@
using System;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Security;
using Moq;
using NUnit.Framework;
@@ -71,7 +72,7 @@ namespace Umbraco.Tests.Testing.TestingTests
Mock.Of<ICultureDictionaryFactory>(),
Mock.Of<IUmbracoComponentRenderer>(),
Mock.Of<IPublishedContentQuery>(),
new MembershipHelper(umbracoContext.HttpContext, Mock.Of<IPublishedMemberCache>(), Mock.Of<MembersMembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IPublicAccessService>(), AppCaches.Disabled, Mock.Of<ILogger>(), ShortStringHelper, Mock.Of<IEntityService>()));
new MembershipHelper(Mock.Of<HttpContextBase>(), Mock.Of<IPublishedMemberCache>(), Mock.Of<MembersMembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IPublicAccessService>(), AppCaches.Disabled, Mock.Of<ILogger>(), ShortStringHelper, Mock.Of<IEntityService>()));
Assert.Pass();
}
@@ -103,7 +104,7 @@ namespace Umbraco.Tests.Testing.TestingTests
var memberService = Mock.Of<IMemberService>();
var memberTypeService = Mock.Of<IMemberTypeService>();
var membershipProvider = new MembersMembershipProvider(memberService, memberTypeService, Mock.Of<IUmbracoVersion>(), TestHelper.GetHostingEnvironment(), TestHelper.GetIpResolver());
var membershipHelper = new MembershipHelper(umbracoContext.HttpContext, Mock.Of<IPublishedMemberCache>(), membershipProvider, Mock.Of<RoleProvider>(), memberService, memberTypeService, Mock.Of<IPublicAccessService>(), AppCaches.Disabled, logger, ShortStringHelper, Mock.Of<IEntityService>());
var membershipHelper = new MembershipHelper(Mock.Of<HttpContextBase>(), Mock.Of<IPublishedMemberCache>(), membershipProvider, Mock.Of<RoleProvider>(), memberService, memberTypeService, Mock.Of<IPublicAccessService>(), AppCaches.Disabled, logger, ShortStringHelper, Mock.Of<IEntityService>());
var umbracoHelper = new UmbracoHelper(Mock.Of<IPublishedContent>(), Mock.Of<ITagQuery>(), Mock.Of<ICultureDictionaryFactory>(), Mock.Of<IUmbracoComponentRenderer>(), Mock.Of<IPublishedContentQuery>(), membershipHelper);
var umbracoMapper = new UmbracoMapper(new MapDefinitionCollection(new[] { Mock.Of<IMapDefinition>() }));
@@ -138,6 +138,7 @@ namespace Umbraco.Tests.Testing
protected IMapperCollection Mappers => Factory.GetInstance<IMapperCollection>();
protected UmbracoMapper Mapper => Factory.GetInstance<UmbracoMapper>();
protected IHttpContextAccessor HttpContextAccessor => Factory.GetInstance<IHttpContextAccessor>();
protected IRuntimeState RuntimeState => ComponentTests.MockRuntimeState(RuntimeLevel.Run);
#endregion
@@ -444,6 +445,9 @@ namespace Umbraco.Tests.Testing
Composition.WithCollectionBuilder<DataEditorCollectionBuilder>();
Composition.RegisterUnique<PropertyEditorCollection>();
Composition.RegisterUnique<ParameterEditorCollection>();
Composition.RegisterUnique<IHttpContextAccessor>(TestObjects.GetHttpContextAccessor());
}
#endregion
@@ -124,7 +124,7 @@ namespace Umbraco.Tests.Web.Mvc
Mock.Of<ICultureDictionaryFactory>(),
Mock.Of<IUmbracoComponentRenderer>(),
Mock.Of<IPublishedContentQuery>(query => query.Content(2) == content.Object),
new MembershipHelper(umbracoContext.HttpContext, Mock.Of<IPublishedMemberCache>(), Mock.Of<MembersMembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IPublicAccessService>(), AppCaches.Disabled, Mock.Of<ILogger>(), ShortStringHelper, Mock.Of<IEntityService>()));
new MembershipHelper(Mock.Of<HttpContextBase>(), Mock.Of<IPublishedMemberCache>(), Mock.Of<MembersMembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IPublicAccessService>(), AppCaches.Disabled, Mock.Of<ILogger>(), ShortStringHelper, Mock.Of<IEntityService>()));
var ctrl = new TestSurfaceController(umbracoContextAccessor, helper);
var result = ctrl.GetContent(2) as PublishedContentResult;
@@ -159,7 +159,7 @@ namespace Umbraco.Tests.Web.Mvc
var content = Mock.Of<IPublishedContent>(publishedContent => publishedContent.Id == 12345);
var contextBase = umbracoContext.HttpContext;
var publishedRouter = BaseWebTest.CreatePublishedRouter(TestObjects.GetUmbracoSettings().WebRouting);
var frequest = publishedRouter.CreateRequest(umbracoContext, new Uri("http://localhost/test"));
frequest.PublishedContent = content;
@@ -173,7 +173,7 @@ namespace Umbraco.Tests.Web.Mvc
routeData.DataTokens.Add(Core.Constants.Web.UmbracoRouteDefinitionDataToken, routeDefinition);
var ctrl = new TestSurfaceController(umbracoContextAccessor, new UmbracoHelper());
ctrl.ControllerContext = new ControllerContext(contextBase, routeData, ctrl);
ctrl.ControllerContext = new ControllerContext(Mock.Of<HttpContextBase>(), routeData, ctrl);
var result = ctrl.GetContentFromCurrentPage() as PublishedContentResult;
@@ -28,12 +28,22 @@ namespace Umbraco.Web
public class BatchedDatabaseServerMessenger : DatabaseServerMessenger
{
private readonly IUmbracoDatabaseFactory _databaseFactory;
private readonly IHttpContextAccessor _httpContextAccessor;
public BatchedDatabaseServerMessenger(
IRuntimeState runtime, IUmbracoDatabaseFactory databaseFactory, IScopeProvider scopeProvider, ISqlContext sqlContext, IProfilingLogger proflog, DatabaseServerMessengerOptions options, IHostingEnvironment hostingEnvironment, CacheRefresherCollection cacheRefreshers)
IRuntimeState runtime,
IUmbracoDatabaseFactory databaseFactory,
IScopeProvider scopeProvider,
ISqlContext sqlContext,
IProfilingLogger proflog,
DatabaseServerMessengerOptions options,
IHostingEnvironment hostingEnvironment,
CacheRefresherCollection cacheRefreshers,
IHttpContextAccessor httpContextAccessor)
: base(runtime, scopeProvider, sqlContext, proflog, true, options, hostingEnvironment, cacheRefreshers)
{
_databaseFactory = databaseFactory;
_httpContextAccessor = httpContextAccessor;
}
// invoked by DatabaseServerRegistrarAndMessengerComponent
@@ -105,7 +115,7 @@ namespace Umbraco.Web
// try get the http context from the UmbracoContext, we do this because in the case we are launching an async
// thread and we know that the cache refreshers will execute, we will ensure the UmbracoContext and therefore we
// can get the http context from it
var httpContext = (Current.UmbracoContext == null ? null : Current.UmbracoContext.HttpContext)
var httpContext = (_httpContextAccessor.HttpContext)
// if this is null, it could be that an async thread is calling this method that we weren't aware of and the UmbracoContext
// wasn't ensured at the beginning of the thread. We can try to see if the HttpContext.Current is available which might be
// the case if the asp.net synchronization context has kicked in
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Helpers;
@@ -8,6 +9,9 @@ using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Web.Mvc;
using Umbraco.Web.Security;
using Current = Umbraco.Web.Composing.Current;
@@ -56,14 +60,14 @@ namespace Umbraco.Web
/// <remarks>
/// See: http://issues.umbraco.org/issue/U4-1614
/// </remarks>
public static MvcHtmlString PreviewBadge(this HtmlHelper helper)
public static MvcHtmlString PreviewBadge(this HtmlHelper helper, IHttpContextAccessor httpContextAccessor, IGlobalSettings globalSettings, IIOHelper ioHelper, IUmbracoSettingsSection umbracoSettingsSection)
{
if (Current.UmbracoContext.InPreviewMode)
{
var htmlBadge =
String.Format(Current.Configs.Settings().Content.PreviewBadge,
Current.IOHelper.ResolveUrl(Current.Configs.Global().UmbracoPath),
Current.UmbracoContext.HttpContext.Server.UrlEncode(Current.UmbracoContext.HttpContext.Request.Path),
String.Format(umbracoSettingsSection.Content.PreviewBadge,
ioHelper.ResolveUrl(globalSettings.UmbracoPath),
WebUtility.UrlEncode(httpContextAccessor.HttpContext.Request.Path),
Current.UmbracoContext.PublishedRequest.PublishedContent.Id);
return new MvcHtmlString(htmlBadge);
}
+1 -1
View File
@@ -4,6 +4,6 @@ namespace Umbraco.Web
{
public interface IHttpContextAccessor
{
HttpContext HttpContext { get; set; }
HttpContextBase HttpContext { get; set; }
}
}
-5
View File
@@ -72,11 +72,6 @@ namespace Umbraco.Web
/// </summary>
PublishedRequest PublishedRequest { get; set; }
/// <summary>
/// Exposes the HttpContext for the current request
/// </summary>
HttpContextBase HttpContext { get; }
/// <summary>
/// Gets the variation context accessor.
/// </summary>
+1 -1
View File
@@ -18,7 +18,7 @@ namespace Umbraco.Web.Install
{
private static HttpClient _httpClient;
private readonly DatabaseBuilder _databaseBuilder;
private readonly HttpContext _httpContext;
private readonly HttpContextBase _httpContext;
private readonly ILogger _logger;
private readonly IGlobalSettings _globalSettings;
private readonly IUmbracoVersion _umbracoVersion;
@@ -23,15 +23,17 @@ namespace Umbraco.Web.Models.Mapping
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly ContentAppFactoryCollection _contentAppDefinitions;
private readonly ILocalizedTextService _localizedTextService;
private readonly IHttpContextAccessor _httpContextAccessor;
public CommonMapper(IUserService userService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IUmbracoContextAccessor umbracoContextAccessor,
ContentAppFactoryCollection contentAppDefinitions, ILocalizedTextService localizedTextService)
ContentAppFactoryCollection contentAppDefinitions, ILocalizedTextService localizedTextService, IHttpContextAccessor httpContextAccessor)
{
_userService = userService;
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;
_umbracoContextAccessor = umbracoContextAccessor;
_contentAppDefinitions = contentAppDefinitions;
_localizedTextService = localizedTextService;
_httpContextAccessor = httpContextAccessor;
}
public UserProfile GetOwner(IContentBase source, MapperContext context)
@@ -65,19 +67,19 @@ namespace Umbraco.Web.Models.Mapping
public string GetTreeNodeUrl<TController>(IContentBase source)
where TController : ContentTreeControllerBase
{
var umbracoContext = _umbracoContextAccessor.UmbracoContext;
if (umbracoContext == null) return null;
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext == null) return null;
var urlHelper = new UrlHelper(umbracoContext.HttpContext.Request.RequestContext);
var urlHelper = new UrlHelper(httpContext.Request.RequestContext);
return urlHelper.GetUmbracoApiService<TController>(controller => controller.GetTreeNode(source.Key.ToString("N"), null));
}
public string GetMemberTreeNodeUrl(IContentBase source)
{
var umbracoContext = _umbracoContextAccessor.UmbracoContext;
if (umbracoContext == null) return null;
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext == null) return null;
var urlHelper = new UrlHelper(umbracoContext.HttpContext.Request.RequestContext);
var urlHelper = new UrlHelper(httpContext.Request.RequestContext);
return urlHelper.GetUmbracoApiService<MemberTreeController>(controller => controller.GetTreeNode(source.Key.ToString("N"), null));
}
@@ -5,11 +5,11 @@ namespace Umbraco.Web
{
internal class AspNetHttpContextAccessor : IHttpContextAccessor
{
public HttpContext HttpContext
public HttpContextBase HttpContext
{
get
{
return HttpContext.Current;
return new HttpContextWrapper(System.Web.HttpContext.Current);
}
set
{
@@ -16,12 +16,14 @@ namespace Umbraco.Web.Routing
public class ContentFinderByIdPath : IContentFinder
{
private readonly ILogger _logger;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IWebRoutingSection _webRoutingSection;
public ContentFinderByIdPath(IWebRoutingSection webRoutingSection, ILogger logger)
public ContentFinderByIdPath(IWebRoutingSection webRoutingSection, ILogger logger, IHttpContextAccessor httpContextAccessor)
{
_webRoutingSection = webRoutingSection ?? throw new System.ArgumentNullException(nameof(webRoutingSection));
_logger = logger ?? throw new System.ArgumentNullException(nameof(logger));
_httpContextAccessor = httpContextAccessor;
}
/// <summary>
@@ -55,10 +57,10 @@ namespace Umbraco.Web.Routing
if (node != null)
{
//if we have a node, check if we have a culture in the query string
if (frequest.UmbracoContext.HttpContext.Request.QueryString.ContainsKey("culture"))
if (_httpContextAccessor.HttpContext.Request.QueryString.ContainsKey("culture"))
{
//we're assuming it will match a culture, if an invalid one is passed in, an exception will throw (there is no TryGetCultureInfo method), i think this is ok though
frequest.Culture = CultureInfo.GetCultureInfo(frequest.UmbracoContext.HttpContext.Request.QueryString["culture"]);
frequest.Culture = CultureInfo.GetCultureInfo(_httpContextAccessor.HttpContext.Request.QueryString["culture"]);
}
frequest.PublishedContent = node;
@@ -9,10 +9,17 @@
/// </remarks>
public class ContentFinderByPageIdQuery : IContentFinder
{
private readonly IHttpContextAccessor _httpContextAccessor;
public ContentFinderByPageIdQuery(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public bool TryFindContent(PublishedRequest frequest)
{
int pageId;
if (int.TryParse(frequest.UmbracoContext.HttpContext.Request["umbPageID"], out pageId))
if (int.TryParse(_httpContextAccessor.HttpContext.Request["umbPageID"], out pageId))
{
var doc = frequest.UmbracoContext.Content.GetById(pageId);
+209 -1
View File
@@ -12,11 +12,219 @@ using Umbraco.Core.Configuration.UmbracoSettings;
namespace Umbraco.Web.Routing
{
public interface IPublishedRequest
{
/// <summary>
/// Gets the UmbracoContext.
/// </summary>
IUmbracoContext UmbracoContext { get; }
/// <summary>
/// Gets or sets the cleaned up Uri used for routing.
/// </summary>
/// <remarks>The cleaned up Uri has no virtual directory, no trailing slash, no .aspx extension, etc.</remarks>
Uri Uri { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the Umbraco Backoffice should ignore a collision for this request.
/// </summary>
bool IgnorePublishedContentCollisions { get; set; }
/// <summary>
/// Gets or sets the requested content.
/// </summary>
/// <remarks>Setting the requested content clears <c>Template</c>.</remarks>
IPublishedContent PublishedContent { get; set; }
/// <summary>
/// Gets the initial requested content.
/// </summary>
/// <remarks>The initial requested content is the content that was found by the finders,
/// before anything such as 404, redirect... took place.</remarks>
IPublishedContent InitialPublishedContent { get; }
/// <summary>
/// Gets value indicating whether the current published content is the initial one.
/// </summary>
bool IsInitialPublishedContent { get; }
/// <summary>
/// Gets or sets a value indicating whether the current published content has been obtained
/// from the initial published content following internal redirections exclusively.
/// </summary>
/// <remarks>Used by PublishedContentRequestEngine.FindTemplate() to figure out whether to
/// apply the internal redirect or not, when content is not the initial content.</remarks>
bool IsInternalRedirectPublishedContent { get; }
/// <summary>
/// Gets a value indicating whether the content request has a content.
/// </summary>
bool HasPublishedContent { get; }
/// <summary>
/// Gets the alias of the template to use to display the requested content.
/// </summary>
string TemplateAlias { get; }
/// <summary>
/// Gets a value indicating whether the content request has a template.
/// </summary>
bool HasTemplate { get; }
/// <summary>
/// Gets or sets the content request's domain.
/// </summary>
/// <remarks>Is a DomainAndUri object ie a standard Domain plus the fully qualified uri. For example,
/// the <c>Domain</c> may contain "example.com" whereas the <c>Uri</c> will be fully qualified eg "http://example.com/".</remarks>
DomainAndUri Domain { get; set; }
/// <summary>
/// Gets a value indicating whether the content request has a domain.
/// </summary>
bool HasDomain { get; }
/// <summary>
/// Gets or sets the content request's culture.
/// </summary>
CultureInfo Culture { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the requested content could not be found.
/// </summary>
/// <remarks>This is set in the <c>PublishedContentRequestBuilder</c> and can also be used in
/// custom content finders or <c>Prepared</c> event handlers, where we want to allow developers
/// to indicate a request is 404 but not to cancel it.</remarks>
bool Is404 { get; set; }
/// <summary>
/// Gets a value indicating whether the content request triggers a redirect (permanent or not).
/// </summary>
bool IsRedirect { get; }
/// <summary>
/// Gets or sets a value indicating whether the redirect is permanent.
/// </summary>
bool IsRedirectPermanent { get; }
/// <summary>
/// Gets or sets the url to redirect to, when the content request triggers a redirect.
/// </summary>
string RedirectUrl { get; }
/// <summary>
/// Gets or sets the content request http response status code.
/// </summary>
/// <remarks>Does not actually set the http response status code, only registers that the response
/// should use the specified code. The code will or will not be used, in due time.</remarks>
int ResponseStatusCode { get; }
/// <summary>
/// Gets or sets the content request http response status description.
/// </summary>
/// <remarks>Does not actually set the http response status description, only registers that the response
/// should use the specified description. The description will or will not be used, in due time.</remarks>
string ResponseStatusDescription { get; }
/// <summary>
/// Gets or sets the <c>System.Web.HttpCacheability</c>
/// </summary>
// Note: we used to set a default value here but that would then be the default
// for ALL requests, we shouldn't overwrite it though if people are using [OutputCache] for example
// see: https://our.umbraco.com/forum/using-umbraco-and-getting-started/79715-output-cache-in-umbraco-752
HttpCacheability Cacheability { get; set; }
/// <summary>
/// Gets or sets a list of Extensions to append to the Response.Cache object.
/// </summary>
List<string> CacheExtensions { get; set; }
/// <summary>
/// Gets or sets a dictionary of Headers to append to the Response object.
/// </summary>
Dictionary<string, string> Headers { get; set; }
/// <summary>
/// Prepares the request.
/// </summary>
void Prepare();
/// <summary>
/// Sets the requested content, following an internal redirect.
/// </summary>
/// <param name="content">The requested content.</param>
/// <remarks>Depending on <c>UmbracoSettings.InternalRedirectPreservesTemplate</c>, will
/// preserve or reset the template, if any.</remarks>
void SetInternalRedirectPublishedContent(IPublishedContent content);
/// <summary>
/// Indicates that the current PublishedContent is the initial one.
/// </summary>
void SetIsInitialPublishedContent();
/// <summary>
/// Tries to set the template to use to display the requested content.
/// </summary>
/// <param name="alias">The alias of the template.</param>
/// <returns>A value indicating whether a valid template with the specified alias was found.</returns>
/// <remarks>
/// <para>Successfully setting the template does refresh <c>RenderingEngine</c>.</para>
/// <para>If setting the template fails, then the previous template (if any) remains in place.</para>
/// </remarks>
bool TrySetTemplate(string alias);
/// <summary>
/// Sets the template to use to display the requested content.
/// </summary>
/// <param name="template">The template.</param>
/// <remarks>Setting the template does refresh <c>RenderingEngine</c>.</remarks>
void SetTemplate(ITemplate template);
/// <summary>
/// Resets the template.
/// </summary>
void ResetTemplate();
/// <summary>
/// Indicates that the content request should trigger a redirect (302).
/// </summary>
/// <param name="url">The url to redirect to.</param>
/// <remarks>Does not actually perform a redirect, only registers that the response should
/// redirect. Redirect will or will not take place in due time.</remarks>
void SetRedirect(string url);
/// <summary>
/// Indicates that the content request should trigger a permanent redirect (301).
/// </summary>
/// <param name="url">The url to redirect to.</param>
/// <remarks>Does not actually perform a redirect, only registers that the response should
/// redirect. Redirect will or will not take place in due time.</remarks>
void SetRedirectPermanent(string url);
/// <summary>
/// Indicates that the content request should trigger a redirect, with a specified status code.
/// </summary>
/// <param name="url">The url to redirect to.</param>
/// <param name="status">The status code (300-308).</param>
/// <remarks>Does not actually perform a redirect, only registers that the response should
/// redirect. Redirect will or will not take place in due time.</remarks>
void SetRedirect(string url, int status);
/// <summary>
/// Sets the http response status code, along with an optional associated description.
/// </summary>
/// <param name="code">The http status code.</param>
/// <param name="description">The description.</param>
/// <remarks>Does not actually set the http response status code and description, only registers that
/// the response should use the specified code and description. The code and description will or will
/// not be used, in due time.</remarks>
void SetResponseStatus(int code, string description = null);
}
/// <summary>
/// Represents a request for one specified Umbraco IPublishedContent to be rendered
/// by one specified template, using one specified Culture and RenderingEngine.
/// </summary>
public class PublishedRequest
public class PublishedRequest : IPublishedRequest
{
private readonly IPublishedRouter _publishedRouter;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
+5 -2
View File
@@ -29,6 +29,7 @@ namespace Umbraco.Web.Routing
private readonly ILogger _logger;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
private readonly IUserService _userService;
private readonly IHttpContextAccessor _httpContextAccessor;
/// <summary>
/// Initializes a new instance of the <see cref="PublishedRouter"/> class.
@@ -41,7 +42,8 @@ namespace Umbraco.Web.Routing
ServiceContext services,
IProfilingLogger proflog,
IUmbracoSettingsSection umbracoSettingsSection,
IUserService userService)
IUserService userService,
IHttpContextAccessor httpContextAccessor)
{
_webRoutingSection = webRoutingSection ?? throw new ArgumentNullException(nameof(webRoutingSection));
_contentFinders = contentFinders ?? throw new ArgumentNullException(nameof(contentFinders));
@@ -52,6 +54,7 @@ namespace Umbraco.Web.Routing
_logger = proflog;
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
_userService = userService ?? throw new ArgumentNullException(nameof(userService));
_httpContextAccessor = httpContextAccessor;
}
/// <inheritdoc />
@@ -651,7 +654,7 @@ namespace Umbraco.Web.Routing
var useAltTemplate = request.IsInitialPublishedContent
|| (_webRoutingSection.InternalRedirectPreservesTemplate && request.IsInternalRedirectPublishedContent);
var altTemplate = useAltTemplate
? request.UmbracoContext.HttpContext.Request[Constants.Conventions.Url.AltTemplate]
? _httpContextAccessor.HttpContext.Request[Constants.Conventions.Url.AltTemplate]
: null;
if (string.IsNullOrWhiteSpace(altTemplate))
@@ -98,7 +98,7 @@ namespace Umbraco.Web.Runtime
// register a per-request HttpContextBase object
// is per-request so only one wrapper is created per request
composition.Register<HttpContextBase>(factory => new HttpContextWrapper(factory.GetInstance<IHttpContextAccessor>().HttpContext), Lifetime.Request);
composition.Register<HttpContextBase>(factory => factory.GetInstance<IHttpContextAccessor>().HttpContext, Lifetime.Request);
// register the published snapshot accessor - the "current" published snapshot is in the umbraco context
composition.RegisterUnique<IPublishedSnapshotAccessor, UmbracoContextPublishedSnapshotAccessor>();
@@ -127,7 +127,7 @@ namespace Umbraco.Web.Templates
//var queryString = _umbracoContext.HttpContext.Request.QueryString.AllKeys
// .ToDictionary(key => key, key => context.Request.QueryString[key]);
var requestContext = new RequestContext(new HttpContextWrapper(_httpContextAccessor.HttpContext), new RouteData()
var requestContext = new RequestContext(_httpContextAccessor.HttpContext, new RouteData()
{
Route = RouteTable.Routes["Umbraco_default"]
});
+1 -1
View File
@@ -789,7 +789,7 @@
</PropertyGroup>
<ItemGroup>
<!-- we want to exclude all facade references ?! -->
<FixedReferencePath Include="@(ReferencePath)" Condition="'%(ReferencePath.FileName)' != 'System.ValueTuple' and '%(ReferencePath.FileName)' != 'System.Net.Http'" />
<FixedReferencePath Include="@(ReferencePath)" Condition="'%(ReferencePath.FileName)' != 'System.ValueTuple' and '%(ReferencePath.FileName)' != 'System.Net.Http' and '%(ReferencePath.FileName)' != 'System.Threading.Tasks.Extensions'" />
</ItemGroup>
<Delete Files="$(TargetDir)$(TargetName).XmlSerializers.dll" ContinueOnError="true" />
<!--
+17 -1
View File
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Web;
using System.Web.Hosting;
using Umbraco.Core.Configuration;
@@ -79,7 +80,7 @@ namespace Umbraco.Web
return new UmbracoContextReference(currentUmbracoContext, false, _umbracoContextAccessor);
httpContext = httpContext ?? new HttpContextWrapper(HttpContext.Current ?? new HttpContext(new SimpleWorkerRequest("null.aspx", "", NullWriterInstance)));
httpContext = EnsureHttpContext(httpContext);
var umbracoContext = CreateUmbracoContext(httpContext);
_umbracoContextAccessor.UmbracoContext = umbracoContext;
@@ -87,6 +88,21 @@ namespace Umbraco.Web
return new UmbracoContextReference(umbracoContext, true, _umbracoContextAccessor);
}
public static HttpContextBase EnsureHttpContext(HttpContextBase httpContext = null)
{
if (Thread.GetDomain().GetData(".appPath") is null || Thread.GetDomain().GetData(".appVPath") is null)
{
return httpContext ?? new HttpContextWrapper(HttpContext.Current ??
new HttpContext(new SimpleWorkerRequest("", "", "null.aspx", "", NullWriterInstance)));
}
else
{
return httpContext ?? new HttpContextWrapper(HttpContext.Current ??
new HttpContext(new SimpleWorkerRequest("null.aspx", "", NullWriterInstance)));
}
}
// dummy TextWriter that does not write
private class NullWriter : TextWriter
{