Merge pull request #8095 from umbraco/netcore/feature/redirect-installer
Redirect to installer and ext method/startup cleanup
This commit is contained in:
@@ -49,6 +49,11 @@
|
||||
/// The default authentication type used for remembering that 2FA is not needed on next login
|
||||
/// </summary>
|
||||
public const string TwoFactorRememberBrowserCookie = "TwoFactorRememberBrowser";
|
||||
|
||||
public static class Mvc
|
||||
{
|
||||
public const string InstallArea = "UmbracoInstall";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ namespace Umbraco.Core
|
||||
.TrimStart("/");
|
||||
|
||||
//check if this is in the umbraco back office
|
||||
return afterAuthority.InvariantStartsWith(hostingEnvironment.ToAbsolute("~/install").TrimStart("/"));
|
||||
return afterAuthority.InvariantStartsWith(hostingEnvironment.ToAbsolute(Constants.SystemDirectories.Install).TrimStart("/"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using LightInject;
|
||||
using LightInject.Microsoft.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System;
|
||||
using Umbraco.Composing;
|
||||
using Umbraco.Core.Composing.LightInject;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.Core.Composing
|
||||
{
|
||||
@@ -12,9 +14,10 @@ namespace Umbraco.Core.Composing
|
||||
/// </summary>
|
||||
public class UmbracoServiceProviderFactory : IServiceProviderFactory<IServiceContainer>
|
||||
{
|
||||
public UmbracoServiceProviderFactory(ServiceContainer container)
|
||||
public UmbracoServiceProviderFactory(ServiceContainer container, bool initializeCurrent)
|
||||
{
|
||||
_container = new LightInjectContainer(container);
|
||||
_initializeCurrent = initializeCurrent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -35,6 +38,7 @@ namespace Umbraco.Core.Composing
|
||||
var container = CreateServiceContainer();
|
||||
UmbracoContainer = _container = new LightInjectContainer(container);
|
||||
IsActive = true;
|
||||
_initializeCurrent = true;
|
||||
}
|
||||
|
||||
// see here for orig lightinject version https://github.com/seesharper/LightInject.Microsoft.DependencyInjection/blob/412566e3f70625e6b96471db5e1f7cd9e3e1eb18/src/LightInject.Microsoft.DependencyInjection/LightInject.Microsoft.DependencyInjection.cs#L263
|
||||
@@ -43,6 +47,7 @@ namespace Umbraco.Core.Composing
|
||||
|
||||
IServiceCollection _services;
|
||||
readonly LightInjectContainer _container;
|
||||
private readonly bool _initializeCurrent;
|
||||
|
||||
internal LightInjectContainer GetContainer() => _container;
|
||||
|
||||
@@ -75,6 +80,20 @@ namespace Umbraco.Core.Composing
|
||||
public IServiceProvider CreateServiceProvider(IServiceContainer containerBuilder)
|
||||
{
|
||||
var provider = containerBuilder.CreateServiceProvider(_services);
|
||||
|
||||
if (_initializeCurrent)
|
||||
{
|
||||
// after cross wiring, configure "Current"
|
||||
Current.Initialize(
|
||||
_container.GetInstance<Umbraco.Core.Logging.ILogger>(),
|
||||
_container.GetInstance<Configs>(),
|
||||
_container.GetInstance<IIOHelper>(),
|
||||
_container.GetInstance<Umbraco.Core.Hosting.IHostingEnvironment>(),
|
||||
_container.GetInstance<IBackOfficeInfo>(),
|
||||
_container.GetInstance<Umbraco.Core.Logging.IProfiler>());
|
||||
}
|
||||
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Umbraco.Tests.Integration
|
||||
|
||||
// LightInject / Umbraco
|
||||
var container = UmbracoServiceProviderFactory.CreateServiceContainer();
|
||||
var serviceProviderFactory = new UmbracoServiceProviderFactory(container);
|
||||
var serviceProviderFactory = new UmbracoServiceProviderFactory(container, false);
|
||||
var umbracoContainer = serviceProviderFactory.GetContainer();
|
||||
serviceProviderFactory.CreateBuilder(services); // called during Host Builder, needed to capture services
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ using Umbraco.Tests.Common;
|
||||
using Umbraco.Tests.Integration.Extensions;
|
||||
using Umbraco.Tests.Integration.Implementations;
|
||||
using Umbraco.Tests.Integration.Testing;
|
||||
using Umbraco.Web.BackOffice.AspNetCore;
|
||||
using Umbraco.Web.Common.AspNetCore;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
@@ -47,7 +46,7 @@ namespace Umbraco.Tests.Integration
|
||||
{
|
||||
// LightInject / Umbraco
|
||||
var container = UmbracoServiceProviderFactory.CreateServiceContainer();
|
||||
var serviceProviderFactory = new UmbracoServiceProviderFactory(container);
|
||||
var serviceProviderFactory = new UmbracoServiceProviderFactory(container, false);
|
||||
var umbracoContainer = serviceProviderFactory.GetContainer();
|
||||
|
||||
// Special case since we are not using the Generic Host, we need to manually add an AspNetCore service to the container
|
||||
|
||||
@@ -17,7 +17,6 @@ using Umbraco.Core.Strings;
|
||||
using Umbraco.Tests.Common.Builders;
|
||||
using Umbraco.Tests.Integration.Extensions;
|
||||
using Umbraco.Tests.Integration.Implementations;
|
||||
using Umbraco.Web.BackOffice.AspNetCore;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Tests.Integration.Testing
|
||||
@@ -35,7 +34,7 @@ namespace Umbraco.Tests.Integration.Testing
|
||||
public static LightInjectContainer GetUmbracoContainer(out UmbracoServiceProviderFactory serviceProviderFactory)
|
||||
{
|
||||
var container = UmbracoServiceProviderFactory.CreateServiceContainer();
|
||||
serviceProviderFactory = new UmbracoServiceProviderFactory(container);
|
||||
serviceProviderFactory = new UmbracoServiceProviderFactory(container, false);
|
||||
var umbracoContainer = serviceProviderFactory.GetContainer();
|
||||
return umbracoContainer;
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.AspNetCore
|
||||
{
|
||||
internal class AspNetCoreHttpContextAccessor //: IHttpContextAccessor
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public AspNetCoreHttpContextAccessor(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public HttpContext HttpContext => _httpContextAccessor.HttpContext;
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Serilog.Context;
|
||||
using Smidge;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Infrastructure.Logging.Serilog.Enrichers;
|
||||
using Umbraco.Web.Common.Middleware;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.AspNetCore
|
||||
{
|
||||
public static class UmbracoApplicationBuilderExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseUmbracoBackOffice(this IApplicationBuilder app)
|
||||
{
|
||||
if (app == null) throw new ArgumentNullException(nameof(app));
|
||||
|
||||
if (!app.UmbracoCanBoot()) return app;
|
||||
|
||||
// TODO: start the back office
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start Umbraco
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseUmbracoCore(this IApplicationBuilder app)
|
||||
{
|
||||
if (app == null) throw new ArgumentNullException(nameof(app));
|
||||
|
||||
if (app.UmbracoCanBoot())
|
||||
{
|
||||
var runtime = app.ApplicationServices.GetRequiredService<IRuntime>();
|
||||
|
||||
// Register a listener for application shutdown in order to terminate the runtime
|
||||
var hostLifetime = app.ApplicationServices.GetRequiredService<IApplicationShutdownRegistry>();
|
||||
var runtimeShutdown = new CoreRuntimeShutdown(runtime, hostLifetime);
|
||||
hostLifetime.RegisterObject(runtimeShutdown);
|
||||
|
||||
// Register our global threadabort enricher for logging
|
||||
var threadAbortEnricher = app.ApplicationServices.GetRequiredService<ThreadAbortExceptionEnricher>();
|
||||
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 :)
|
||||
|
||||
}
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures the runtime is shutdown when the application is shutting down
|
||||
/// </summary>
|
||||
private class CoreRuntimeShutdown : IRegisteredObject
|
||||
{
|
||||
public CoreRuntimeShutdown(IRuntime runtime, IApplicationShutdownRegistry hostLifetime)
|
||||
{
|
||||
_runtime = runtime;
|
||||
_hostLifetime = hostLifetime;
|
||||
}
|
||||
|
||||
private bool _completed = false;
|
||||
private readonly IRuntime _runtime;
|
||||
private readonly IApplicationShutdownRegistry _hostLifetime;
|
||||
|
||||
public void Stop(bool immediate)
|
||||
{
|
||||
if (!_completed)
|
||||
{
|
||||
_completed = true;
|
||||
_runtime.Terminate();
|
||||
_hostLifetime.UnregisterObject(this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseUmbracoRequestLogging(this IApplicationBuilder app)
|
||||
{
|
||||
if (app == null) throw new ArgumentNullException(nameof(app));
|
||||
|
||||
if (!app.UmbracoCanBoot()) return app;
|
||||
|
||||
app.UseMiddleware<UmbracoRequestLoggingMiddleware>();
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseUmbracoRuntimeMinification(this IApplicationBuilder app)
|
||||
{
|
||||
if (app == null) throw new ArgumentNullException(nameof(app));
|
||||
|
||||
if (!app.UmbracoCanBoot()) return app;
|
||||
|
||||
app.UseSmidge();
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using SixLabors.ImageSharp.Web.DependencyInjection;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
public static class UmbracoBackOfficeApplicationBuilderExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseUmbracoBackOffice(this IApplicationBuilder app)
|
||||
{
|
||||
if (app == null) throw new ArgumentNullException(nameof(app));
|
||||
|
||||
if (!app.UmbracoCanBoot()) return app;
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
// TODO: This is temporary, 'umbraco' cannot be hard coded, needs to use GetUmbracoMvcArea()
|
||||
// but actually we need to route all back office stuff in a back office area like we do in v8
|
||||
|
||||
// TODO: We will also need to detect runtime state here and redirect to the installer,
|
||||
// Potentially switch this to dynamic routing so we can essentially disable/overwrite the back office routes to redirect to install
|
||||
// when required, example https://www.strathweb.com/2019/08/dynamic-controller-routing-in-asp-net-core-3-0/
|
||||
|
||||
endpoints.MapControllerRoute("Backoffice", "/umbraco/{Action}", new
|
||||
{
|
||||
Controller = "BackOffice",
|
||||
Action = "Default"
|
||||
});
|
||||
});
|
||||
|
||||
app.UseUmbracoRuntimeMinification();
|
||||
|
||||
// Important we handle image manipulations before the static files, otherwise the querystring is just ignored.
|
||||
// TODO: Since we are dependent on these we need to register them but what happens when we call this multiple times since we are dependent on this for UseUmbracoWebsite too?
|
||||
app.UseImageSharp();
|
||||
app.UseStaticFiles();
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,18 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Serilog.Context;
|
||||
using Smidge;
|
||||
using StackExchange.Profiling;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Infrastructure.Logging.Serilog.Enrichers;
|
||||
using Umbraco.Web.Common.Middleware;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
|
||||
public static class ApplicationBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
@@ -21,6 +27,42 @@ namespace Umbraco.Extensions
|
||||
return runtime.State.Level > RuntimeLevel.BootFailed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Start Umbraco
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseUmbracoCore(this IApplicationBuilder app)
|
||||
{
|
||||
if (app == null) throw new ArgumentNullException(nameof(app));
|
||||
|
||||
if (app.UmbracoCanBoot())
|
||||
{
|
||||
var runtime = app.ApplicationServices.GetRequiredService<IRuntime>();
|
||||
|
||||
// Register a listener for application shutdown in order to terminate the runtime
|
||||
var hostLifetime = app.ApplicationServices.GetRequiredService<IApplicationShutdownRegistry>();
|
||||
var runtimeShutdown = new CoreRuntimeShutdown(runtime, hostLifetime);
|
||||
hostLifetime.RegisterObject(runtimeShutdown);
|
||||
|
||||
// Register our global threadabort enricher for logging
|
||||
var threadAbortEnricher = app.ApplicationServices.GetRequiredService<ThreadAbortExceptionEnricher>();
|
||||
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 :)
|
||||
|
||||
}
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables middlewares required to run Umbraco
|
||||
/// </summary>
|
||||
@@ -37,6 +79,60 @@ namespace Umbraco.Extensions
|
||||
app.UseMiddleware<MiniProfilerMiddleware>();
|
||||
return app;
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseUmbracoRequestLogging(this IApplicationBuilder app)
|
||||
{
|
||||
if (app == null) throw new ArgumentNullException(nameof(app));
|
||||
|
||||
if (!app.UmbracoCanBoot()) return app;
|
||||
|
||||
app.UseMiddleware<UmbracoRequestLoggingMiddleware>();
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables runtime minification for Umbraco
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseUmbracoRuntimeMinification(this IApplicationBuilder app)
|
||||
{
|
||||
if (app == null) throw new ArgumentNullException(nameof(app));
|
||||
|
||||
if (!app.UmbracoCanBoot()) return app;
|
||||
|
||||
app.UseSmidge();
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures the runtime is shutdown when the application is shutting down
|
||||
/// </summary>
|
||||
private class CoreRuntimeShutdown : IRegisteredObject
|
||||
{
|
||||
public CoreRuntimeShutdown(IRuntime runtime, IApplicationShutdownRegistry hostLifetime)
|
||||
{
|
||||
_runtime = runtime;
|
||||
_hostLifetime = hostLifetime;
|
||||
}
|
||||
|
||||
private bool _completed = false;
|
||||
private readonly IRuntime _runtime;
|
||||
private readonly IApplicationShutdownRegistry _hostLifetime;
|
||||
|
||||
public void Stop(bool immediate)
|
||||
{
|
||||
if (!_completed)
|
||||
{
|
||||
_completed = true;
|
||||
_runtime.Terminate();
|
||||
_hostLifetime.UnregisterObject(this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using Umbraco.Core;
|
||||
using Umbraco.Web.Common.Controllers;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
@@ -101,30 +102,26 @@ namespace Umbraco.Extensions
|
||||
if (controllerName == null) throw new ArgumentNullException(nameof(controllerName));
|
||||
if (string.IsNullOrWhiteSpace(controllerName)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(controllerName));
|
||||
|
||||
string routeName;
|
||||
if (area.IsNullOrWhiteSpace())
|
||||
{
|
||||
routeName = string.Format("umbraco-{0}-{1}", "api", controllerName);
|
||||
if (id == null)
|
||||
{
|
||||
|
||||
return url.RouteUrl(routeName, new { controller = controllerName, action = actionName, httproute = "" });
|
||||
return url.Action(actionName, controllerName);
|
||||
}
|
||||
else
|
||||
{
|
||||
return url.RouteUrl(routeName, new { controller = controllerName, action = actionName, id = id, httproute = "" });
|
||||
return url.Action(actionName, controllerName, new { id = id });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
routeName = string.Format("umbraco-{0}-{1}-{2}", "api", area, controllerName);
|
||||
if (id == null)
|
||||
{
|
||||
return url.RouteUrl(routeName, new { controller = controllerName, action = actionName, httproute = "" });
|
||||
return url.Action(actionName, controllerName, new { area = area });
|
||||
}
|
||||
else
|
||||
{
|
||||
return url.RouteUrl(routeName, new { controller = controllerName, action = actionName, id = id, httproute = "" });
|
||||
return url.Action(actionName, controllerName, new { area = area, id = id });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Web;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
public static class UmbracoInstallApplicationBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Enables the Umbraco installer
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseUmbracoInstaller(this IApplicationBuilder app)
|
||||
{
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
var runtime = app.ApplicationServices.GetRequiredService<IRuntimeState>();
|
||||
var logger = app.ApplicationServices.GetRequiredService<ILogger>();
|
||||
var uriUtility = app.ApplicationServices.GetRequiredService<UriUtility>();
|
||||
switch (runtime.Level)
|
||||
{
|
||||
case RuntimeLevel.Install:
|
||||
case RuntimeLevel.Upgrade:
|
||||
|
||||
var installPath = uriUtility.ToAbsolute(Constants.SystemDirectories.Install).EnsureEndsWith('/');
|
||||
|
||||
endpoints.MapAreaControllerRoute(
|
||||
"umbraco-install-api",
|
||||
Umbraco.Core.Constants.Web.Mvc.InstallArea,
|
||||
$"{installPath}api/{{Action}}",
|
||||
new { controller = "InstallApi" });
|
||||
|
||||
endpoints.MapAreaControllerRoute(
|
||||
"umbraco-install",
|
||||
Umbraco.Core.Constants.Web.Mvc.InstallArea,
|
||||
$"{installPath}{{controller}}/{{Action}}",
|
||||
new { controller = "Install", action = "Index" });
|
||||
|
||||
// TODO: Potentially switch this to dynamic routing so we can essentially disable/overwrite the back office routes to redirect to install,
|
||||
// example https://www.strathweb.com/2019/08/dynamic-controller-routing-in-asp-net-core-3-0/
|
||||
|
||||
// register catch all because if we are in install/upgrade mode then we'll catch everything and redirect
|
||||
endpoints.MapGet("{*url}", context =>
|
||||
{
|
||||
var uri = context.Request.GetEncodedUrl();
|
||||
// redirect to install
|
||||
ReportRuntime(logger, runtime.Level, "Umbraco must install or upgrade.");
|
||||
|
||||
var installUrl = $"{installPath}?redir=true&url={uri}";
|
||||
context.Response.Redirect(installUrl, false);
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
private static bool _reported;
|
||||
private static RuntimeLevel _reportedLevel;
|
||||
|
||||
private static void ReportRuntime(ILogger logger, RuntimeLevel level, string message)
|
||||
{
|
||||
if (_reported && _reportedLevel == level) return;
|
||||
_reported = true;
|
||||
_reportedLevel = level;
|
||||
logger.Warn(typeof(UmbracoInstallApplicationBuilderExtensions), message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,6 +20,7 @@ using Smidge.Nuglify;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Web.Common.ApplicationModels;
|
||||
using Umbraco.Web.Common.Middleware;
|
||||
using Umbraco.Web.Common.ModelBinding;
|
||||
|
||||
namespace Umbraco.Extensions
|
||||
@@ -33,6 +34,9 @@ namespace Umbraco.Extensions
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddUmbracoWebComponents(this IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<UmbracoRequestLoggingMiddleware>();
|
||||
services.AddTransient<UmbracoRequestMiddleware>();
|
||||
|
||||
services.TryAddSingleton<UmbracoJsonModelBinder>();
|
||||
services.ConfigureOptions<UmbracoMvcConfigureOptions>();
|
||||
services.TryAddEnumerable(ServiceDescriptor.Transient<IApplicationModelProvider, UmbracoApiBehaviorApplicationModelProvider>());
|
||||
|
||||
@@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Semver;
|
||||
|
||||
|
||||
namespace Umbraco.Web
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
public static class ViewDataExtensions
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Web.Common.Install
|
||||
[TypeFilter(typeof(HttpResponseExceptionFilter))]
|
||||
[TypeFilter(typeof(AngularJsonOnlyConfigurationAttribute))]
|
||||
[HttpInstallAuthorize]
|
||||
[Area("Install")]
|
||||
[Area(Umbraco.Core.Constants.Web.Mvc.InstallArea)]
|
||||
public class InstallApiController : ControllerBase
|
||||
{
|
||||
private readonly DatabaseBuilder _databaseBuilder;
|
||||
|
||||
@@ -14,12 +14,10 @@ namespace Umbraco.Web.Common.Install
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The MVC Installation controller
|
||||
/// The Installation controller
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// NOTE: All views must have their full paths as we do not have a custom view engine for the installation views!
|
||||
/// </remarks>
|
||||
[InstallAuthorize]
|
||||
[Area(Umbraco.Core.Constants.Web.Mvc.InstallArea)]
|
||||
public class InstallController : Controller
|
||||
{
|
||||
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
|
||||
@@ -72,7 +70,7 @@ namespace Umbraco.Web.Common.Install
|
||||
}
|
||||
|
||||
// gen the install base urlAddUmbracoCore
|
||||
ViewData.SetInstallApiBaseUrl(Url.GetUmbracoApiService("GetSetup", "InstallApi", "UmbracoInstall").TrimEnd("GetSetup"));
|
||||
ViewData.SetInstallApiBaseUrl(Url.GetUmbracoApiService("GetSetup", "InstallApi", Umbraco.Core.Constants.Web.Mvc.InstallArea).TrimEnd("GetSetup"));
|
||||
|
||||
// get the base umbraco folder
|
||||
ViewData.SetUmbracoBaseFolder(_hostingEnvironment.ToAbsolute(_globalSettings.UmbracoPath));
|
||||
@@ -81,7 +79,6 @@ namespace Umbraco.Web.Common.Install
|
||||
|
||||
await _installHelper.InstallStatus(false, "");
|
||||
|
||||
// always ensure full path (see NOTE in the class remarks)
|
||||
return View();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,30 +8,28 @@ using Umbraco.Core.Logging.Serilog.Enrichers;
|
||||
|
||||
namespace Umbraco.Web.Common.Middleware
|
||||
{
|
||||
public class UmbracoRequestLoggingMiddleware
|
||||
public class UmbracoRequestLoggingMiddleware : IMiddleware
|
||||
{
|
||||
readonly RequestDelegate _next;
|
||||
private readonly HttpSessionIdEnricher _sessionIdEnricher;
|
||||
private readonly HttpRequestNumberEnricher _requestNumberEnricher;
|
||||
private readonly HttpRequestIdEnricher _requestIdEnricher;
|
||||
|
||||
public UmbracoRequestLoggingMiddleware(RequestDelegate next,
|
||||
public UmbracoRequestLoggingMiddleware(
|
||||
HttpSessionIdEnricher sessionIdEnricher,
|
||||
HttpRequestNumberEnricher requestNumberEnricher,
|
||||
HttpRequestIdEnricher requestIdEnricher)
|
||||
{
|
||||
_next = next;
|
||||
_sessionIdEnricher = sessionIdEnricher;
|
||||
_requestNumberEnricher = requestNumberEnricher;
|
||||
_requestIdEnricher = requestIdEnricher;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext httpContext)
|
||||
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
|
||||
{
|
||||
// do not process if client-side request
|
||||
if (new Uri(httpContext.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsClientSideRequest())
|
||||
if (new Uri(context.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsClientSideRequest())
|
||||
{
|
||||
await _next(httpContext);
|
||||
await next(context);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -42,7 +40,7 @@ namespace Umbraco.Web.Common.Middleware
|
||||
using (LogContext.Push(_requestNumberEnricher))
|
||||
using (LogContext.Push(_requestIdEnricher))
|
||||
{
|
||||
await _next(httpContext);
|
||||
await next(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,46 +5,46 @@ using Microsoft.AspNetCore.Http.Extensions;
|
||||
using Umbraco.Web.Common.Lifetime;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using System.Threading;
|
||||
|
||||
namespace Umbraco.Web.Common.Middleware
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Manages Umbraco request objects and their lifetime
|
||||
/// </summary>
|
||||
public class UmbracoRequestMiddleware
|
||||
public class UmbracoRequestMiddleware : IMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IUmbracoRequestLifetimeManager _umbracoRequestLifetimeManager;
|
||||
private readonly IUmbracoContextFactory _umbracoContextFactory;
|
||||
|
||||
public UmbracoRequestMiddleware(RequestDelegate next,
|
||||
public UmbracoRequestMiddleware(
|
||||
ILogger logger,
|
||||
IUmbracoRequestLifetimeManager umbracoRequestLifetimeManager,
|
||||
IUmbracoContextFactory umbracoContextFactory)
|
||||
{
|
||||
_next = next;
|
||||
_logger = logger;
|
||||
_umbracoRequestLifetimeManager = umbracoRequestLifetimeManager;
|
||||
_umbracoContextFactory = umbracoContextFactory;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
|
||||
{
|
||||
// do not process if client-side request
|
||||
|
||||
if (new Uri(context.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsClientSideRequest())
|
||||
{
|
||||
await _next(context);
|
||||
await next(context);
|
||||
return;
|
||||
}
|
||||
|
||||
var umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
_umbracoRequestLifetimeManager.InitRequest(context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -53,7 +53,7 @@ namespace Umbraco.Web.Common.Middleware
|
||||
_logger.Error<UmbracoRequestMiddleware>(ex);
|
||||
}
|
||||
|
||||
await _next(context);
|
||||
await next(context);
|
||||
|
||||
_umbracoRequestLifetimeManager.EndRequest(context);
|
||||
}
|
||||
|
||||
@@ -99,10 +99,5 @@ namespace Umbraco.Web
|
||||
return new UmbracoContextReference(umbracoContext, true, _umbracoContextAccessor);
|
||||
}
|
||||
|
||||
// dummy TextWriter that does not write
|
||||
private class NullWriter : TextWriter
|
||||
{
|
||||
public override Encoding Encoding => Encoding.UTF8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@using Umbraco.Web
|
||||
@using Umbraco.Extensions
|
||||
@using Umbraco.Composing
|
||||
@{
|
||||
Layout = null;
|
||||
@@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
|
||||
|
||||
namespace Umbraco.Web.UI.BackOffice
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
// GET: /<controller>/
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.SqlClient;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Umbraco.Composing;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Web.BackOffice.AspNetCore;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Web.Common.Filters;
|
||||
using Umbraco.Web.Website.AspNetCore;
|
||||
using IHostingEnvironment = Umbraco.Core.Hosting.IHostingEnvironment;
|
||||
|
||||
|
||||
namespace Umbraco.Web.UI.BackOffice
|
||||
{
|
||||
@@ -62,24 +42,11 @@ namespace Umbraco.Web.UI.BackOffice
|
||||
{
|
||||
options.ShouldProfile = request => false; // WebProfiler determine and start profiling. We should not use the MiniProfilerMiddleware to also profile
|
||||
});
|
||||
|
||||
//Finally initialize Current
|
||||
// TODO: This should be moved to the UmbracoServiceProviderFactory when the container is cross-wired and then don't use the overload above to `out var factory`
|
||||
Current.Initialize(
|
||||
factory.GetInstance<ILogger> (),
|
||||
factory.GetInstance<Configs>(),
|
||||
factory.GetInstance<IIOHelper>(),
|
||||
factory.GetInstance<IHostingEnvironment>(),
|
||||
factory.GetInstance<IBackOfficeInfo>(),
|
||||
factory.GetInstance<IProfiler>()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
|
||||
//app.UseMiniProfiler();
|
||||
if (_env.IsDevelopment())
|
||||
{
|
||||
@@ -89,29 +56,15 @@ namespace Umbraco.Web.UI.BackOffice
|
||||
app.UseStatusCodePages();
|
||||
app.UseRouting();
|
||||
|
||||
|
||||
app.UseUmbracoRouting();
|
||||
app.UseUmbracoCore();
|
||||
app.UseUmbracoRouting();
|
||||
app.UseUmbracoRequestLogging();
|
||||
app.UseUmbracoWebsite();
|
||||
app.UseUmbracoBackOffice();
|
||||
app.UseUmbracoRuntimeMinification();
|
||||
|
||||
app.UseUmbracoBackOffice();
|
||||
app.UseUmbracoInstaller();
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllerRoute("Backoffice", "/umbraco/{Action}", new
|
||||
{
|
||||
Controller = "BackOffice",
|
||||
Action = "Default"
|
||||
});
|
||||
|
||||
// TODO: Fix this routing with an area
|
||||
endpoints.MapControllerRoute("Install", "/install/{controller}/{Action}", defaults:new { Area = "Install"});
|
||||
|
||||
//TODO register routing correct: Name must be like this
|
||||
endpoints.MapControllerRoute("umbraco-api-UmbracoInstall-InstallApi", "/install/api/{Action}", defaults:new { Area = "Install", Controller = "InstallApi"});
|
||||
|
||||
{
|
||||
endpoints.MapControllerRoute(
|
||||
name: "default",
|
||||
pattern: "{controller}/{action=Index}/{id?}");
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Views\" />
|
||||
<Folder Include="wwwroot\Media" />
|
||||
<Folder Include="wwwroot\Umbraco\views\install" />
|
||||
</ItemGroup>
|
||||
@@ -40,7 +41,7 @@
|
||||
<Content Remove="wwwroot\Umbraco\views\install\continueinstall.html" />
|
||||
<Content Remove="wwwroot\Umbraco\views\install\database.html" />
|
||||
<Content Remove="wwwroot\Umbraco\views\install\error.html" />
|
||||
<Content Update="Views\Install\Index.cshtml">
|
||||
<Content Update="Areas\UmbracoInstall\Views\Install\Index.cshtml">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using SixLabors.ImageSharp.Web.DependencyInjection;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Web.Website.AspNetCore
|
||||
namespace Umbraco.Extensions
|
||||
{
|
||||
public static class UmbracoBackOfficeApplicationBuilderExtensions
|
||||
public static class UmbracoWebsiteApplicationBuilderExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseUmbracoWebsite(this IApplicationBuilder app)
|
||||
{
|
||||
@@ -16,6 +13,7 @@ namespace Umbraco.Web.Website.AspNetCore
|
||||
if (!app.UmbracoCanBoot()) return app;
|
||||
|
||||
// Important we handle image manipulations before the static files, otherwise the querystring is just ignored.
|
||||
// TODO: Since we are dependent on these we need to register them but what happens when we call this multiple times since we are dependent on this for UseUmbracoBackOffice too?
|
||||
app.UseImageSharp();
|
||||
app.UseStaticFiles();
|
||||
|
||||
Reference in New Issue
Block a user