diff --git a/src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs b/src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs index 72848753e5..875117afbc 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByIdTests.cs @@ -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().WebRouting, Logger); + var lookup = new ContentFinderByIdPath(Factory.GetInstance().WebRouting, Logger, HttpContextAccessor); var result = lookup.TryFindContent(frequest); diff --git a/src/Umbraco.Tests/Routing/ContentFinderByPageIdQueryTests.cs b/src/Umbraco.Tests/Routing/ContentFinderByPageIdQueryTests.cs index c1abb5a3a5..20bbeb92d4 100644 --- a/src/Umbraco.Tests/Routing/ContentFinderByPageIdQueryTests.cs +++ b/src/Umbraco.Tests/Routing/ContentFinderByPageIdQueryTests.cs @@ -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(); + 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); diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index 4bcb08925d..a5b5ba29a2 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -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()), 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(), context => { var membershipHelper = new MembershipHelper( - umbracoContext.HttpContext, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), AppCaches.Disabled, Mock.Of(), ShortStringHelper, Mock.Of()); + httpContext, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), AppCaches.Disabled, Mock.Of(), ShortStringHelper, Mock.Of()); return new CustomDocumentController(Factory.GetInstance(), umbracoContextAccessor, Factory.GetInstance(), @@ -161,7 +165,7 @@ namespace Umbraco.Tests.Routing new UmbracoHelper(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), 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), diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs index 176664b467..ee922cdfcb 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs @@ -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.CreatePartial(), new ProfilingLogger(Mock.Of(), Mock.Of()), container?.TryGetInstance() ?? Current.Factory.GetInstance(), - Mock.Of()); + Mock.Of(), + Mock.Of()); } } } diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs index 70c3707b04..12282d1603 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects-Mocks.cs @@ -337,5 +337,16 @@ namespace Umbraco.Tests.TestHelpers } #endregion + + public IHttpContextAccessor GetHttpContextAccessor(HttpContextBase httpContextBase = null) + { + var mock = new Mock(); + + var httpContext = UmbracoContextFactory.EnsureHttpContext(httpContextBase); + + mock.Setup(x => x.HttpContext).Returns(httpContext); + + return mock.Object; + } } } diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs index faeb5b10ec..82cc0b196e 100644 --- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs @@ -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() + .Add(Composition.TypeLoader.GetUmbracoApiControllers()); + Composition.RegisterUnique(f => { if (Options.Database == UmbracoTestOptions.Database.None) diff --git a/src/Umbraco.Tests/Testing/Objects/Accessors/NoHttpContextAccessor.cs b/src/Umbraco.Tests/Testing/Objects/Accessors/NoHttpContextAccessor.cs index 9b37389241..e34ff7bb45 100644 --- a/src/Umbraco.Tests/Testing/Objects/Accessors/NoHttpContextAccessor.cs +++ b/src/Umbraco.Tests/Testing/Objects/Accessors/NoHttpContextAccessor.cs @@ -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; } } diff --git a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs index 724eb29266..b712bcafc8 100644 --- a/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs +++ b/src/Umbraco.Tests/Testing/TestingTests/MockTests.cs @@ -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(), Mock.Of(), Mock.Of(), - new MembershipHelper(umbracoContext.HttpContext, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), AppCaches.Disabled, Mock.Of(), ShortStringHelper, Mock.Of())); + new MembershipHelper(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), AppCaches.Disabled, Mock.Of(), ShortStringHelper, Mock.Of())); Assert.Pass(); } @@ -103,7 +104,7 @@ namespace Umbraco.Tests.Testing.TestingTests var memberService = Mock.Of(); var memberTypeService = Mock.Of(); var membershipProvider = new MembersMembershipProvider(memberService, memberTypeService, Mock.Of(), TestHelper.GetHostingEnvironment(), TestHelper.GetIpResolver()); - var membershipHelper = new MembershipHelper(umbracoContext.HttpContext, Mock.Of(), membershipProvider, Mock.Of(), memberService, memberTypeService, Mock.Of(), AppCaches.Disabled, logger, ShortStringHelper, Mock.Of()); + var membershipHelper = new MembershipHelper(Mock.Of(), Mock.Of(), membershipProvider, Mock.Of(), memberService, memberTypeService, Mock.Of(), AppCaches.Disabled, logger, ShortStringHelper, Mock.Of()); var umbracoHelper = new UmbracoHelper(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), membershipHelper); var umbracoMapper = new UmbracoMapper(new MapDefinitionCollection(new[] { Mock.Of() })); diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs index 93a3e52446..7999898c4e 100644 --- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs +++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs @@ -138,6 +138,7 @@ namespace Umbraco.Tests.Testing protected IMapperCollection Mappers => Factory.GetInstance(); protected UmbracoMapper Mapper => Factory.GetInstance(); + protected IHttpContextAccessor HttpContextAccessor => Factory.GetInstance(); protected IRuntimeState RuntimeState => ComponentTests.MockRuntimeState(RuntimeLevel.Run); #endregion @@ -444,6 +445,9 @@ namespace Umbraco.Tests.Testing Composition.WithCollectionBuilder(); Composition.RegisterUnique(); Composition.RegisterUnique(); + + + Composition.RegisterUnique(TestObjects.GetHttpContextAccessor()); } #endregion diff --git a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs index c54192f869..6a75fe5457 100644 --- a/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/SurfaceControllerTests.cs @@ -124,7 +124,7 @@ namespace Umbraco.Tests.Web.Mvc Mock.Of(), Mock.Of(), Mock.Of(query => query.Content(2) == content.Object), - new MembershipHelper(umbracoContext.HttpContext, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), AppCaches.Disabled, Mock.Of(), ShortStringHelper, Mock.Of())); + new MembershipHelper(Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of(), AppCaches.Disabled, Mock.Of(), ShortStringHelper, Mock.Of())); 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(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(), routeData, ctrl); var result = ctrl.GetContentFromCurrentPage() as PublishedContentResult; diff --git a/src/Umbraco.Web/BatchedDatabaseServerMessenger.cs b/src/Umbraco.Web/BatchedDatabaseServerMessenger.cs index 5662883d2a..8a6862b018 100644 --- a/src/Umbraco.Web/BatchedDatabaseServerMessenger.cs +++ b/src/Umbraco.Web/BatchedDatabaseServerMessenger.cs @@ -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 diff --git a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs index d71f90aab5..38de699b7d 100644 --- a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs +++ b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs @@ -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 /// /// See: http://issues.umbraco.org/issue/U4-1614 /// - 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); } diff --git a/src/Umbraco.Web/IHttpContextAccessor.cs b/src/Umbraco.Web/IHttpContextAccessor.cs index a00632803d..c83b9425a6 100644 --- a/src/Umbraco.Web/IHttpContextAccessor.cs +++ b/src/Umbraco.Web/IHttpContextAccessor.cs @@ -4,6 +4,6 @@ namespace Umbraco.Web { public interface IHttpContextAccessor { - HttpContext HttpContext { get; set; } + HttpContextBase HttpContext { get; set; } } } diff --git a/src/Umbraco.Web/IUmbracoContext.cs b/src/Umbraco.Web/IUmbracoContext.cs index 7609ad6b01..c0cee5e9ff 100644 --- a/src/Umbraco.Web/IUmbracoContext.cs +++ b/src/Umbraco.Web/IUmbracoContext.cs @@ -72,11 +72,6 @@ namespace Umbraco.Web /// PublishedRequest PublishedRequest { get; set; } - /// - /// Exposes the HttpContext for the current request - /// - HttpContextBase HttpContext { get; } - /// /// Gets the variation context accessor. /// diff --git a/src/Umbraco.Web/Install/InstallHelper.cs b/src/Umbraco.Web/Install/InstallHelper.cs index db13ff1ed7..fb809d1bfc 100644 --- a/src/Umbraco.Web/Install/InstallHelper.cs +++ b/src/Umbraco.Web/Install/InstallHelper.cs @@ -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; diff --git a/src/Umbraco.Web/Models/Mapping/CommonMapper.cs b/src/Umbraco.Web/Models/Mapping/CommonMapper.cs index 7bf4a94b1c..ed047d2ad8 100644 --- a/src/Umbraco.Web/Models/Mapping/CommonMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/CommonMapper.cs @@ -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(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(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(controller => controller.GetTreeNode(source.Key.ToString("N"), null)); } diff --git a/src/Umbraco.Web/Net/AspNetHttpContextAccessor.cs b/src/Umbraco.Web/Net/AspNetHttpContextAccessor.cs index babd8dfcfa..c7270a8259 100644 --- a/src/Umbraco.Web/Net/AspNetHttpContextAccessor.cs +++ b/src/Umbraco.Web/Net/AspNetHttpContextAccessor.cs @@ -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 { diff --git a/src/Umbraco.Web/Routing/ContentFinderByIdPath.cs b/src/Umbraco.Web/Routing/ContentFinderByIdPath.cs index b339198928..5e0e3b2ace 100644 --- a/src/Umbraco.Web/Routing/ContentFinderByIdPath.cs +++ b/src/Umbraco.Web/Routing/ContentFinderByIdPath.cs @@ -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; } /// @@ -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; diff --git a/src/Umbraco.Web/Routing/ContentFinderByPageIdQuery.cs b/src/Umbraco.Web/Routing/ContentFinderByPageIdQuery.cs index 70a920f6f0..eb1abbb718 100644 --- a/src/Umbraco.Web/Routing/ContentFinderByPageIdQuery.cs +++ b/src/Umbraco.Web/Routing/ContentFinderByPageIdQuery.cs @@ -9,10 +9,17 @@ /// 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); diff --git a/src/Umbraco.Web/Routing/PublishedRequest.cs b/src/Umbraco.Web/Routing/PublishedRequest.cs index becdbc8d27..13074fce07 100644 --- a/src/Umbraco.Web/Routing/PublishedRequest.cs +++ b/src/Umbraco.Web/Routing/PublishedRequest.cs @@ -12,11 +12,219 @@ using Umbraco.Core.Configuration.UmbracoSettings; namespace Umbraco.Web.Routing { + public interface IPublishedRequest + { + /// + /// Gets the UmbracoContext. + /// + IUmbracoContext UmbracoContext { get; } + + /// + /// Gets or sets the cleaned up Uri used for routing. + /// + /// The cleaned up Uri has no virtual directory, no trailing slash, no .aspx extension, etc. + Uri Uri { get; set; } + + /// + /// Gets or sets a value indicating whether the Umbraco Backoffice should ignore a collision for this request. + /// + bool IgnorePublishedContentCollisions { get; set; } + + /// + /// Gets or sets the requested content. + /// + /// Setting the requested content clears Template. + IPublishedContent PublishedContent { get; set; } + + /// + /// Gets the initial requested content. + /// + /// The initial requested content is the content that was found by the finders, + /// before anything such as 404, redirect... took place. + IPublishedContent InitialPublishedContent { get; } + + /// + /// Gets value indicating whether the current published content is the initial one. + /// + bool IsInitialPublishedContent { get; } + + /// + /// Gets or sets a value indicating whether the current published content has been obtained + /// from the initial published content following internal redirections exclusively. + /// + /// Used by PublishedContentRequestEngine.FindTemplate() to figure out whether to + /// apply the internal redirect or not, when content is not the initial content. + bool IsInternalRedirectPublishedContent { get; } + + /// + /// Gets a value indicating whether the content request has a content. + /// + bool HasPublishedContent { get; } + + /// + /// Gets the alias of the template to use to display the requested content. + /// + string TemplateAlias { get; } + + /// + /// Gets a value indicating whether the content request has a template. + /// + bool HasTemplate { get; } + + /// + /// Gets or sets the content request's domain. + /// + /// Is a DomainAndUri object ie a standard Domain plus the fully qualified uri. For example, + /// the Domain may contain "example.com" whereas the Uri will be fully qualified eg "http://example.com/". + DomainAndUri Domain { get; set; } + + /// + /// Gets a value indicating whether the content request has a domain. + /// + bool HasDomain { get; } + + /// + /// Gets or sets the content request's culture. + /// + CultureInfo Culture { get; set; } + + /// + /// Gets or sets a value indicating whether the requested content could not be found. + /// + /// This is set in the PublishedContentRequestBuilder and can also be used in + /// custom content finders or Prepared event handlers, where we want to allow developers + /// to indicate a request is 404 but not to cancel it. + bool Is404 { get; set; } + + /// + /// Gets a value indicating whether the content request triggers a redirect (permanent or not). + /// + bool IsRedirect { get; } + + /// + /// Gets or sets a value indicating whether the redirect is permanent. + /// + bool IsRedirectPermanent { get; } + + /// + /// Gets or sets the url to redirect to, when the content request triggers a redirect. + /// + string RedirectUrl { get; } + + /// + /// Gets or sets the content request http response status code. + /// + /// 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. + int ResponseStatusCode { get; } + + /// + /// Gets or sets the content request http response status description. + /// + /// 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. + string ResponseStatusDescription { get; } + + /// + /// Gets or sets the System.Web.HttpCacheability + /// +// 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; } + + /// + /// Gets or sets a list of Extensions to append to the Response.Cache object. + /// + List CacheExtensions { get; set; } + + /// + /// Gets or sets a dictionary of Headers to append to the Response object. + /// + Dictionary Headers { get; set; } + + /// + /// Prepares the request. + /// + void Prepare(); + + /// + /// Sets the requested content, following an internal redirect. + /// + /// The requested content. + /// Depending on UmbracoSettings.InternalRedirectPreservesTemplate, will + /// preserve or reset the template, if any. + void SetInternalRedirectPublishedContent(IPublishedContent content); + + /// + /// Indicates that the current PublishedContent is the initial one. + /// + void SetIsInitialPublishedContent(); + + /// + /// Tries to set the template to use to display the requested content. + /// + /// The alias of the template. + /// A value indicating whether a valid template with the specified alias was found. + /// + /// Successfully setting the template does refresh RenderingEngine. + /// If setting the template fails, then the previous template (if any) remains in place. + /// + bool TrySetTemplate(string alias); + + /// + /// Sets the template to use to display the requested content. + /// + /// The template. + /// Setting the template does refresh RenderingEngine. + void SetTemplate(ITemplate template); + + /// + /// Resets the template. + /// + void ResetTemplate(); + + /// + /// Indicates that the content request should trigger a redirect (302). + /// + /// The url to redirect to. + /// Does not actually perform a redirect, only registers that the response should + /// redirect. Redirect will or will not take place in due time. + void SetRedirect(string url); + + /// + /// Indicates that the content request should trigger a permanent redirect (301). + /// + /// The url to redirect to. + /// Does not actually perform a redirect, only registers that the response should + /// redirect. Redirect will or will not take place in due time. + void SetRedirectPermanent(string url); + + /// + /// Indicates that the content request should trigger a redirect, with a specified status code. + /// + /// The url to redirect to. + /// The status code (300-308). + /// Does not actually perform a redirect, only registers that the response should + /// redirect. Redirect will or will not take place in due time. + void SetRedirect(string url, int status); + + /// + /// Sets the http response status code, along with an optional associated description. + /// + /// The http status code. + /// The description. + /// 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. + void SetResponseStatus(int code, string description = null); + } + /// /// Represents a request for one specified Umbraco IPublishedContent to be rendered /// by one specified template, using one specified Culture and RenderingEngine. /// - public class PublishedRequest + public class PublishedRequest : IPublishedRequest { private readonly IPublishedRouter _publishedRouter; private readonly IUmbracoSettingsSection _umbracoSettingsSection; diff --git a/src/Umbraco.Web/Routing/PublishedRouter.cs b/src/Umbraco.Web/Routing/PublishedRouter.cs index 82041f04fa..1afbaceccf 100644 --- a/src/Umbraco.Web/Routing/PublishedRouter.cs +++ b/src/Umbraco.Web/Routing/PublishedRouter.cs @@ -29,6 +29,7 @@ namespace Umbraco.Web.Routing private readonly ILogger _logger; private readonly IUmbracoSettingsSection _umbracoSettingsSection; private readonly IUserService _userService; + private readonly IHttpContextAccessor _httpContextAccessor; /// /// Initializes a new instance of the 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; } /// @@ -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)) diff --git a/src/Umbraco.Web/Runtime/WebInitialComposer.cs b/src/Umbraco.Web/Runtime/WebInitialComposer.cs index 48d1a58b2d..e283b4d6a0 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComposer.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComposer.cs @@ -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(factory => new HttpContextWrapper(factory.GetInstance().HttpContext), Lifetime.Request); + composition.Register(factory => factory.GetInstance().HttpContext, Lifetime.Request); // register the published snapshot accessor - the "current" published snapshot is in the umbraco context composition.RegisterUnique(); diff --git a/src/Umbraco.Web/Templates/TemplateRenderer.cs b/src/Umbraco.Web/Templates/TemplateRenderer.cs index 4b0093f910..ba7a42630a 100644 --- a/src/Umbraco.Web/Templates/TemplateRenderer.cs +++ b/src/Umbraco.Web/Templates/TemplateRenderer.cs @@ -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"] }); diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index a02b3d6c55..408951eba6 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -789,7 +789,7 @@ - +