diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index 4b5992ac23..48d739b172 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -378,7 +378,7 @@ namespace Umbraco.Web.Editors "externalLogins", new Dictionary { { - "providers", _httpContextAccessor.HttpContext.GetOwinContext().Authentication.GetExternalAuthenticationTypes() + "providers", _httpContextAccessor.GetRequiredHttpContext().GetOwinContext().Authentication.GetExternalAuthenticationTypes() .Where(p => p.Properties.ContainsKey("UmbracoBackOffice")) .Select(p => new { @@ -465,7 +465,7 @@ namespace Umbraco.Web.Editors app.Add("cacheBuster", $"{version}.{_runtimeState.Level}.{ClientDependencySettings.Instance.Version}".GenerateHash()); //useful for dealing with virtual paths on the client side when hosted in virtual directories especially - app.Add("applicationPath", _httpContextAccessor.HttpContext.Request.ApplicationPath.EnsureEndsWith('/')); + app.Add("applicationPath", _httpContextAccessor.GetRequiredHttpContext().Request.ApplicationPath.EnsureEndsWith('/')); //add the server's GMT time offset in minutes app.Add("serverTimeOffset", Convert.ToInt32(DateTimeOffset.Now.Offset.TotalMinutes)); diff --git a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs index d361ca0af2..796a3a0c4a 100644 --- a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs +++ b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs @@ -67,7 +67,7 @@ namespace Umbraco.Web var htmlBadge = String.Format(umbracoSettingsSection.Content.PreviewBadge, ioHelper.ResolveUrl(globalSettings.UmbracoPath), - WebUtility.UrlEncode(httpContextAccessor.HttpContext.Request.Path), + WebUtility.UrlEncode(httpContextAccessor.GetRequiredHttpContext().Request.Path), Current.UmbracoContext.PublishedRequest.PublishedContent.Id); return new MvcHtmlString(htmlBadge); } diff --git a/src/Umbraco.Web/HttpContextAccessorExtensions.cs b/src/Umbraco.Web/HttpContextAccessorExtensions.cs new file mode 100644 index 0000000000..4c2dcf0a0d --- /dev/null +++ b/src/Umbraco.Web/HttpContextAccessorExtensions.cs @@ -0,0 +1,17 @@ +using System.IO; +using System.Web; + +namespace Umbraco.Web +{ + public static class HttpContextAccessorExtensions + { + public static HttpContextBase GetRequiredHttpContext(this IHttpContextAccessor httpContextAccessor) + { + var httpContext = httpContextAccessor.HttpContext; + + if(httpContext is null) throw new IOException("HttpContext is null"); + + return httpContext; + } + } +} diff --git a/src/Umbraco.Web/Install/InstallHelper.cs b/src/Umbraco.Web/Install/InstallHelper.cs index fb809d1bfc..0c3e945029 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 HttpContextBase _httpContext; + private readonly IHttpContextAccessor _httpContextAccessor; private readonly ILogger _logger; private readonly IGlobalSettings _globalSettings; private readonly IUmbracoVersion _umbracoVersion; @@ -29,7 +29,7 @@ namespace Umbraco.Web.Install DatabaseBuilder databaseBuilder, ILogger logger, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IConnectionStrings connectionStrings) { - _httpContext = httpContextAccessor.HttpContext; + _httpContextAccessor = httpContextAccessor; _logger = logger; _globalSettings = globalSettings; _umbracoVersion = umbracoVersion; @@ -46,12 +46,13 @@ namespace Umbraco.Web.Install { try { - var userAgent = _httpContext.Request.UserAgent; + var httpContext = _httpContextAccessor.GetRequiredHttpContext(); + var userAgent = httpContext.Request.UserAgent; // Check for current install Id var installId = Guid.NewGuid(); - var installCookie = _httpContext.Request.GetCookieValue(Constants.Web.InstallerCookieName); + var installCookie = httpContext.Request.GetCookieValue(Constants.Web.InstallerCookieName); if (string.IsNullOrEmpty(installCookie) == false) { if (Guid.TryParse(installCookie, out installId)) @@ -61,7 +62,7 @@ namespace Umbraco.Web.Install installId = Guid.NewGuid(); } } - _httpContext.Response.Cookies.Set(new HttpCookie(Constants.Web.InstallerCookieName, "1")); + httpContext.Response.Cookies.Set(new HttpCookie(Constants.Web.InstallerCookieName, "1")); var dbProvider = string.Empty; if (IsBrandNewInstall == false) diff --git a/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs index c898532116..e47a8f4b5f 100644 --- a/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs @@ -56,7 +56,7 @@ namespace Umbraco.Web.Install.InstallSteps throw new InvalidOperationException("Could not find the super user!"); } - var userManager = _httpContextAccessor.HttpContext.GetOwinContext().GetBackOfficeUserManager(); + var userManager = _httpContextAccessor.GetRequiredHttpContext().GetOwinContext().GetBackOfficeUserManager(); var membershipUser = await userManager.FindByIdAsync(Constants.Security.SuperUserId); if (membershipUser == null) { diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs index 37e514b370..c9688fed4c 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs @@ -34,7 +34,7 @@ namespace Umbraco.Web.Install.InstallSteps InstallBusinessLogic(packageId); - UmbracoApplication.Restart(_httContextAccessor.HttpContext); + UmbracoApplication.Restart(_httContextAccessor.GetRequiredHttpContext()); return Task.FromResult(null); } diff --git a/src/Umbraco.Web/Net/AspNetHttpContextAccessor.cs b/src/Umbraco.Web/Net/AspNetHttpContextAccessor.cs index 322e9f2d88..d222d18438 100644 --- a/src/Umbraco.Web/Net/AspNetHttpContextAccessor.cs +++ b/src/Umbraco.Web/Net/AspNetHttpContextAccessor.cs @@ -11,12 +11,7 @@ namespace Umbraco.Web { var httpContext = System.Web.HttpContext.Current; - if (httpContext is null) - { - throw new InvalidOperationException("HttpContext is not available"); - } - - return new HttpContextWrapper(httpContext); + return httpContext is null ? null : new HttpContextWrapper(httpContext); } set { diff --git a/src/Umbraco.Web/Routing/ContentFinderByIdPath.cs b/src/Umbraco.Web/Routing/ContentFinderByIdPath.cs index 52d07300ab..bf7d5ef7c4 100644 --- a/src/Umbraco.Web/Routing/ContentFinderByIdPath.cs +++ b/src/Umbraco.Web/Routing/ContentFinderByIdPath.cs @@ -56,11 +56,12 @@ namespace Umbraco.Web.Routing if (node != null) { + var httpContext = _httpContextAccessor.GetRequiredHttpContext(); //if we have a node, check if we have a culture in the query string - if (_httpContextAccessor.HttpContext.Request.QueryString.ContainsKey("culture")) + if (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(_httpContextAccessor.HttpContext.Request.QueryString["culture"]); + frequest.Culture = CultureInfo.GetCultureInfo(httpContext.Request.QueryString["culture"]); } frequest.PublishedContent = node; diff --git a/src/Umbraco.Web/Routing/ContentFinderByPageIdQuery.cs b/src/Umbraco.Web/Routing/ContentFinderByPageIdQuery.cs index 790da3cc89..fb79e13dbc 100644 --- a/src/Umbraco.Web/Routing/ContentFinderByPageIdQuery.cs +++ b/src/Umbraco.Web/Routing/ContentFinderByPageIdQuery.cs @@ -19,7 +19,7 @@ public bool TryFindContent(IPublishedRequest frequest) { int pageId; - if (int.TryParse(_httpContextAccessor.HttpContext.Request["umbPageID"], out pageId)) + if (int.TryParse(_httpContextAccessor.GetRequiredHttpContext().Request["umbPageID"], out pageId)) { var doc = frequest.UmbracoContext.Content.GetById(pageId); diff --git a/src/Umbraco.Web/Routing/PublishedRouter.cs b/src/Umbraco.Web/Routing/PublishedRouter.cs index 7d827b935e..1a6048e4ec 100644 --- a/src/Umbraco.Web/Routing/PublishedRouter.cs +++ b/src/Umbraco.Web/Routing/PublishedRouter.cs @@ -637,7 +637,7 @@ namespace Umbraco.Web.Routing var useAltTemplate = request.IsInitialPublishedContent || (_webRoutingSection.InternalRedirectPreservesTemplate && request.IsInternalRedirectPublishedContent); var altTemplate = useAltTemplate - ? _httpContextAccessor.HttpContext.Request[Constants.Conventions.Url.AltTemplate] + ? _httpContextAccessor.GetRequiredHttpContext().Request[Constants.Conventions.Url.AltTemplate] : null; if (string.IsNullOrWhiteSpace(altTemplate)) diff --git a/src/Umbraco.Web/Security/WebSecurity.cs b/src/Umbraco.Web/Security/WebSecurity.cs index a1b360bb83..6f16eb3c52 100644 --- a/src/Umbraco.Web/Security/WebSecurity.cs +++ b/src/Umbraco.Web/Security/WebSecurity.cs @@ -61,7 +61,7 @@ namespace Umbraco.Web.Security { if (_signInManager == null) { - var mgr = _httpContextAccessor.HttpContext.GetOwinContext().Get(); + var mgr = _httpContextAccessor.GetRequiredHttpContext().GetOwinContext().Get(); if (mgr == null) { throw new NullReferenceException("Could not resolve an instance of " + typeof(BackOfficeSignInManager) + " from the " + typeof(IOwinContext)); @@ -74,12 +74,13 @@ namespace Umbraco.Web.Security private BackOfficeUserManager _userManager; protected BackOfficeUserManager UserManager - => _userManager ?? (_userManager = _httpContextAccessor.HttpContext.GetOwinContext().GetBackOfficeUserManager()); + => _userManager ?? (_userManager = _httpContextAccessor.GetRequiredHttpContext().GetOwinContext().GetBackOfficeUserManager()); [Obsolete("This needs to be removed, ASP.NET Identity should always be used for this operation, this is currently only used in the installer which needs to be updated")] public double PerformLogin(int userId) { - var owinCtx = _httpContextAccessor.HttpContext.GetOwinContext(); + var httpContext = _httpContextAccessor.GetRequiredHttpContext(); + var owinCtx = httpContext.GetOwinContext(); //ensure it's done for owin too owinCtx.Authentication.SignOut(Constants.Security.BackOfficeExternalAuthenticationType); @@ -87,7 +88,7 @@ namespace Umbraco.Web.Security SignInManager.SignInAsync(user, isPersistent: true, rememberBrowser: false).Wait(); - _httpContextAccessor.HttpContext.SetPrincipalForRequest(owinCtx.Request.User); + httpContext.SetPrincipalForRequest(owinCtx.Request.User); return TimeSpan.FromMinutes(_globalSettings.TimeOutInMinutes).TotalSeconds; } @@ -95,8 +96,9 @@ namespace Umbraco.Web.Security [Obsolete("This needs to be removed, ASP.NET Identity should always be used for this operation, this is currently only used in the installer which needs to be updated")] public void ClearCurrentLogin() { - _httpContextAccessor.HttpContext.UmbracoLogout(); - _httpContextAccessor.HttpContext.GetOwinContext().Authentication.SignOut( + var httpContext = _httpContextAccessor.GetRequiredHttpContext(); + httpContext.UmbracoLogout(); + httpContext.GetOwinContext().Authentication.SignOut( Core.Constants.Security.BackOfficeAuthenticationType, Core.Constants.Security.BackOfficeExternalAuthenticationType); } @@ -108,7 +110,7 @@ namespace Umbraco.Web.Security /// public Attempt GetUserId() { - var identity = _httpContextAccessor.HttpContext.GetCurrentIdentity(false); + var identity = _httpContextAccessor.GetRequiredHttpContext().GetCurrentIdentity(false); return identity == null ? Attempt.Fail() : Attempt.Succeed(Convert.ToInt32(identity.Id)); } @@ -143,7 +145,7 @@ namespace Umbraco.Web.Security var user = CurrentUser; // Check for console access - if (user == null || (requiresApproval && user.IsApproved == false) || (user.IsLockedOut && RequestIsInUmbracoApplication(_httpContextAccessor.HttpContext, _globalSettings, _ioHelper))) + if (user == null || (requiresApproval && user.IsApproved == false) || (user.IsLockedOut && RequestIsInUmbracoApplication(_httpContextAccessor, _globalSettings, _ioHelper))) { if (throwExceptions) throw new ArgumentException("You have no privileges to the umbraco console. Please contact your administrator"); return ValidateRequestAttempt.FailedNoPrivileges; @@ -152,9 +154,9 @@ namespace Umbraco.Web.Security } - private static bool RequestIsInUmbracoApplication(HttpContextBase context, IGlobalSettings globalSettings, IIOHelper ioHelper) + private static bool RequestIsInUmbracoApplication(IHttpContextAccessor httpContextAccessor, IGlobalSettings globalSettings, IIOHelper ioHelper) { - return context.Request.Path.ToLower().IndexOf(ioHelper.ResolveUrl(globalSettings.UmbracoPath).ToLower(), StringComparison.Ordinal) > -1; + return httpContextAccessor.GetRequiredHttpContext().Request.Path.ToLower().IndexOf(ioHelper.ResolveUrl(globalSettings.UmbracoPath).ToLower(), StringComparison.Ordinal) > -1; } /// @@ -165,7 +167,7 @@ namespace Umbraco.Web.Security public ValidateRequestAttempt AuthorizeRequest(bool throwExceptions = false) { // check for secure connection - if (_globalSettings.UseHttps && _httpContextAccessor.HttpContext.Request.IsSecureConnection == false) + if (_globalSettings.UseHttps && _httpContextAccessor.GetRequiredHttpContext().Request.IsSecureConnection == false) { if (throwExceptions) throw new SecurityException("This installation requires a secure connection (via SSL). Please update the URL to include https://"); return ValidateRequestAttempt.FailedNoSsl; @@ -191,7 +193,7 @@ namespace Umbraco.Web.Security public bool IsAuthenticated() { var httpContext = _httpContextAccessor.HttpContext; - return httpContext.User != null && httpContext.User.Identity.IsAuthenticated && httpContext.GetCurrentIdentity(false) != null; + return httpContext?.User != null && httpContext.User.Identity.IsAuthenticated && httpContext.GetCurrentIdentity(false) != null; } } diff --git a/src/Umbraco.Web/Templates/TemplateRenderer.cs b/src/Umbraco.Web/Templates/TemplateRenderer.cs index da5de1055c..ac08258ee2 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(_httpContextAccessor.HttpContext, new RouteData() + var requestContext = new RequestContext(_httpContextAccessor.GetRequiredHttpContext(), new RouteData() { Route = RouteTable.Routes["Umbraco_default"] }); diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 388b5b10dc..fa0fe5eda8 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -156,6 +156,7 @@ + diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index 2dacc60e73..99d0b68d89 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -53,7 +53,7 @@ namespace Umbraco.Web // // all in all, this context may be disposed more than once, but DisposableObject ensures that // it is ok and it will be actually disposed only once. - httpContextAccessor.HttpContext.DisposeOnPipelineCompleted(this); + httpContextAccessor.GetRequiredHttpContext().DisposeOnPipelineCompleted(this); ObjectCreated = DateTime.Now; UmbracoRequestId = Guid.NewGuid(); @@ -203,7 +203,7 @@ namespace Umbraco.Web { try { - return _httpContextAccessor.HttpContext.Request; + return _httpContextAccessor.GetRequiredHttpContext().Request; } catch (HttpException) {