From 3d9603e669faf80f6f8be10d2497d115c5883c4b Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 14 May 2020 22:50:27 +1000 Subject: [PATCH] Migrates more logic from the umb module over to netcore --- .../ApplicationBuilderExtensions.cs | 51 +++++----- .../Install/InstallController.cs | 4 + .../UmbracoRequestLoggingMiddleware.cs | 3 + .../Middleware/UmbracoRequestMiddleware.cs | 93 +++++++++++++++++-- src/Umbraco.Web/UmbracoInjectedModule.cs | 93 +------------------ 5 files changed, 121 insertions(+), 123 deletions(-) diff --git a/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs index a43094a8f9..bce4c2430e 100644 --- a/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs @@ -27,8 +27,6 @@ namespace Umbraco.Extensions return runtime.State.Level > RuntimeLevel.BootFailed; } - - /// /// Start Umbraco /// @@ -38,27 +36,19 @@ namespace Umbraco.Extensions { if (app == null) throw new ArgumentNullException(nameof(app)); - if (app.UmbracoCanBoot()) - { - var runtime = app.ApplicationServices.GetRequiredService(); + var runtime = app.ApplicationServices.GetRequiredService(); - // Register a listener for application shutdown in order to terminate the runtime - var hostLifetime = app.ApplicationServices.GetRequiredService(); - var runtimeShutdown = new CoreRuntimeShutdown(runtime, hostLifetime); - hostLifetime.RegisterObject(runtimeShutdown); + // Register a listener for application shutdown in order to terminate the runtime + var hostLifetime = app.ApplicationServices.GetRequiredService(); + var runtimeShutdown = new CoreRuntimeShutdown(runtime, hostLifetime); + hostLifetime.RegisterObject(runtimeShutdown); - // Register our global threadabort enricher for logging - var threadAbortEnricher = app.ApplicationServices.GetRequiredService(); - LogContext.Push(threadAbortEnricher); // NOTE: We are not in a using clause because we are not removing it, it is on the global context + // Register our global threadabort enricher for logging + var threadAbortEnricher = app.ApplicationServices.GetRequiredService(); + LogContext.Push(threadAbortEnricher); // NOTE: We are not in a using clause because we are not removing it, it is on the global context - // Start the runtime! - runtime.Start(); - } - else - { - // TODO: Register simple middleware to show the error like we used to in UmbracoModule? Or maybe that's part of a UseUmbracoWebsite/backoffice type thing .. probably :) - - } + // Start the runtime! + runtime.Start(); return app; } @@ -73,15 +63,24 @@ namespace Umbraco.Extensions { if (app == null) throw new ArgumentNullException(nameof(app)); - app.UseMiddleware(); - - if (!app.UmbracoCanBoot()) return app; - - app.UseMiddleware(); - app.UseMiddleware(); + if (!app.UmbracoCanBoot()) + { + app.UseMiddleware(); + } + else + { + app.UseMiddleware(); + app.UseMiddleware(); + } + return app; } + /// + /// Adds request based serilog enrichers to the LogContext for each request + /// + /// + /// public static IApplicationBuilder UseUmbracoRequestLogging(this IApplicationBuilder app) { if (app == null) throw new ArgumentNullException(nameof(app)); diff --git a/src/Umbraco.Web.Common/Install/InstallController.cs b/src/Umbraco.Web.Common/Install/InstallController.cs index 6614f2d577..a4f659379f 100644 --- a/src/Umbraco.Web.Common/Install/InstallController.cs +++ b/src/Umbraco.Web.Common/Install/InstallController.cs @@ -92,6 +92,10 @@ namespace Umbraco.Web.Common.Install return View(); } + /// + /// Used to perform the redirect to the installer when the runtime level is or + /// + /// [HttpGet] public ActionResult Redirect() { diff --git a/src/Umbraco.Web.Common/Middleware/UmbracoRequestLoggingMiddleware.cs b/src/Umbraco.Web.Common/Middleware/UmbracoRequestLoggingMiddleware.cs index 803eb95d62..febf939d03 100644 --- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestLoggingMiddleware.cs +++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestLoggingMiddleware.cs @@ -8,6 +8,9 @@ using Umbraco.Core.Logging.Serilog.Enrichers; namespace Umbraco.Web.Common.Middleware { + /// + /// Adds request based serilog enrichers to the LogContext for each request + /// public class UmbracoRequestLoggingMiddleware : IMiddleware { private readonly HttpSessionIdEnricher _sessionIdEnricher; diff --git a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs index e1662e834f..6cf3929e06 100644 --- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs +++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs @@ -6,6 +6,8 @@ using Umbraco.Web.Common.Lifetime; using Umbraco.Core; using Umbraco.Core.Logging; using System.Threading; +using Umbraco.Core.Cache; +using System.Collections.Generic; namespace Umbraco.Web.Common.Middleware { @@ -18,22 +20,26 @@ namespace Umbraco.Web.Common.Middleware private readonly ILogger _logger; private readonly IUmbracoRequestLifetimeManager _umbracoRequestLifetimeManager; private readonly IUmbracoContextFactory _umbracoContextFactory; + private readonly IRequestCache _requestCache; public UmbracoRequestMiddleware( ILogger logger, IUmbracoRequestLifetimeManager umbracoRequestLifetimeManager, - IUmbracoContextFactory umbracoContextFactory) + IUmbracoContextFactory umbracoContextFactory, + IRequestCache requestCache) { _logger = logger; _umbracoRequestLifetimeManager = umbracoRequestLifetimeManager; _umbracoContextFactory = umbracoContextFactory; + _requestCache = requestCache; } public async Task InvokeAsync(HttpContext context, RequestDelegate next) { - // do not process if client-side request + var requestUri = new Uri(context.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute); - if (new Uri(context.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsClientSideRequest()) + // do not process if client-side request + if (requestUri.IsClientSideRequest()) { await next(context); return; @@ -43,6 +49,12 @@ namespace Umbraco.Web.Common.Middleware try { + if (umbracoContextReference.UmbracoContext.IsFrontEndUmbracoRequest) + { + LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, _requestCache); + _logger.Verbose("Begin request [{HttpRequestId}]: {RequestUrl}", httpRequestId, requestUri); + } + try { _umbracoRequestLifetimeManager.InitRequest(context); @@ -52,15 +64,80 @@ namespace Umbraco.Web.Common.Middleware // try catch so we don't kill everything in all requests _logger.Error(ex); } - - await next(context); - - _umbracoRequestLifetimeManager.EndRequest(context); + finally + { + try + { + await next(context); + } + finally + { + _umbracoRequestLifetimeManager.EndRequest(context); + } + } } finally { - umbracoContextReference.Dispose(); + if (umbracoContextReference.UmbracoContext.IsFrontEndUmbracoRequest) + { + LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, _requestCache); + _logger.Verbose("End Request [{HttpRequestId}]: {RequestUrl} ({RequestDuration}ms)", httpRequestId, requestUri, DateTime.Now.Subtract(umbracoContextReference.UmbracoContext.ObjectCreated).TotalMilliseconds); + } + + try + { + DisposeRequestCacheItems(_logger, _requestCache, requestUri); + } + finally + { + umbracoContextReference.Dispose(); + } } } + + /// + /// Any object that is in the HttpContext.Items collection that is IDisposable will get disposed on the end of the request + /// + /// + /// + /// + private static void DisposeRequestCacheItems(ILogger logger, IRequestCache requestCache, Uri requestUri) + { + // do not process if client-side request + if (requestUri.IsClientSideRequest()) + return; + + //get a list of keys to dispose + var keys = new HashSet(); + foreach (var i in requestCache) + { + if (i.Value is IDisposeOnRequestEnd || i.Key is IDisposeOnRequestEnd) + { + keys.Add(i.Key); + } + } + //dispose each item and key that was found as disposable. + foreach (var k in keys) + { + try + { + requestCache.Get(k).DisposeIfDisposable(); + } + catch (Exception ex) + { + logger.Error("Could not dispose item with key " + k, ex); + } + try + { + k.DisposeIfDisposable(); + } + catch (Exception ex) + { + logger.Error("Could not dispose item key " + k, ex); + } + } + } + + } } diff --git a/src/Umbraco.Web/UmbracoInjectedModule.cs b/src/Umbraco.Web/UmbracoInjectedModule.cs index 95adb9c64e..a63e305ce2 100644 --- a/src/Umbraco.Web/UmbracoInjectedModule.cs +++ b/src/Umbraco.Web/UmbracoInjectedModule.cs @@ -210,11 +210,9 @@ namespace Umbraco.Web case RuntimeLevel.Install: case RuntimeLevel.Upgrade: - // redirect to install - ReportRuntime(level, "Umbraco must install or upgrade."); - var installPath = _uriUtility.ToAbsolute(Constants.SystemDirectories.Install); - var installUrl = $"{installPath}/?redir=true&url={HttpUtility.UrlEncode(uri.ToString())}"; - httpContext.Response.Redirect(installUrl, true); + + // NOTE: We have moved the logic that was here to netcore already + return false; // cannot serve content default: @@ -222,17 +220,6 @@ namespace Umbraco.Web } } - private static bool _reported; - private static RuntimeLevel _reportedLevel; - - private void ReportRuntime(RuntimeLevel level, string message) - { - if (_reported && _reportedLevel == level) return; - _reported = true; - _reportedLevel = level; - _logger.Warn(message); - } - // ensures Umbraco has at least one published node // if not, rewrites to splash and return false // if yes, return true @@ -309,47 +296,7 @@ namespace Umbraco.Web } - /// - /// Any object that is in the HttpContext.Items collection that is IDisposable will get disposed on the end of the request - /// - /// - private void DisposeRequestCacheItems(HttpContext http, IRequestCache requestCache) - { - // do not process if client-side request - if (http.Request.Url.IsClientSideRequest()) - return; - - //get a list of keys to dispose - var keys = new HashSet(); - foreach (var i in requestCache) - { - if (i.Value is IDisposeOnRequestEnd || i.Key is IDisposeOnRequestEnd) - { - keys.Add(i.Key); - } - } - //dispose each item and key that was found as disposable. - foreach (var k in keys) - { - try - { - requestCache.Get(k).DisposeIfDisposable(); - } - catch (Exception ex) - { - _logger.Error("Could not dispose item with key " + k, ex); - } - try - { - k.DisposeIfDisposable(); - } - catch (Exception ex) - { - _logger.Error("Could not dispose item key " + k, ex); - } - } - } - + #endregion #region IHttpModule @@ -365,32 +312,9 @@ namespace Umbraco.Web { var httpContext = ((HttpApplication) sender).Context; - LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, _requestCache); - - _logger.Verbose("Begin request [{HttpRequestId}]: {RequestUrl}", httpRequestId, httpContext.Request.Url); BeginRequest(new HttpContextWrapper(httpContext)); }; - //disable asp.net headers (security) - // This is the correct place to modify headers according to MS: - // https://our.umbraco.com/forum/umbraco-7/using-umbraco-7/65241-Heap-error-from-header-manipulation?p=0#comment220889 - app.PostReleaseRequestState += (sender, args) => - { - var httpContext = ((HttpApplication) sender).Context; - try - { - httpContext.Response.Headers.Remove("Server"); - //this doesn't normally work since IIS sets it but we'll keep it here anyways. - httpContext.Response.Headers.Remove("X-Powered-By"); - httpContext.Response.Headers.Remove("X-AspNet-Version"); - httpContext.Response.Headers.Remove("X-AspNetMvc-Version"); - } - catch (PlatformNotSupportedException) - { - // can't remove headers this way on IIS6 or cassini. - } - }; - app.PostAuthenticateRequest += (sender, e) => { var httpContext = ((HttpApplication) sender).Context; @@ -408,16 +332,7 @@ namespace Umbraco.Web { var httpContext = ((HttpApplication) sender).Context; - if (Current.UmbracoContext != null && Current.UmbracoContext.IsFrontEndUmbracoRequest) - { - LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, _requestCache); - - _logger.Verbose("End Request [{HttpRequestId}]: {RequestUrl} ({RequestDuration}ms)", httpRequestId, httpContext.Request.Url, DateTime.Now.Subtract(Current.UmbracoContext.ObjectCreated).TotalMilliseconds); - } - UmbracoModule.OnEndRequest(this, new UmbracoRequestEventArgs(Current.UmbracoContext)); - - DisposeRequestCacheItems(httpContext, _requestCache); }; }