Merge remote-tracking branch 'origin/netcore/netcore' into netcore/feature/AB6586-migrate_controllers
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System.Net.Mail;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Configuration
|
||||
@@ -8,5 +9,10 @@ namespace Umbraco.Configuration
|
||||
public string Host { get; set; }
|
||||
public int Port { get; set; }
|
||||
public string PickupDirectoryLocation { get; set; }
|
||||
public SmtpDeliveryMethod DeliveryMethod { get; set; }
|
||||
|
||||
public string Username { get; set; }
|
||||
|
||||
public string Password { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Mail;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
@@ -72,10 +73,10 @@ namespace Umbraco.Configuration.Models
|
||||
_configuration.GetValue(Prefix + "NoNodesViewPath", "~/config/splashes/NoNodes.cshtml");
|
||||
|
||||
public bool IsSmtpServerConfigured =>
|
||||
_configuration.GetSection(Constants.Configuration.ConfigPrefix + "Smtp")?.GetChildren().Any() ?? false;
|
||||
_configuration.GetSection(Constants.Configuration.ConfigGlobalPrefix + "Smtp")?.GetChildren().Any() ?? false;
|
||||
|
||||
public ISmtpSettings SmtpSettings =>
|
||||
new SmtpSettingsImpl(_configuration.GetSection(Constants.Configuration.ConfigPrefix + "Smtp"));
|
||||
new SmtpSettingsImpl(_configuration.GetSection(Constants.Configuration.ConfigGlobalPrefix + "Smtp"));
|
||||
|
||||
private class SmtpSettingsImpl : ISmtpSettings
|
||||
{
|
||||
@@ -90,6 +91,11 @@ namespace Umbraco.Configuration.Models
|
||||
public string Host => _configurationSection.GetValue<string>("Host");
|
||||
public int Port => _configurationSection.GetValue<int>("Port");
|
||||
public string PickupDirectoryLocation => _configurationSection.GetValue<string>("PickupDirectoryLocation");
|
||||
public SmtpDeliveryMethod DeliveryMethod => _configurationSection.GetValue<SmtpDeliveryMethod>("DeliveryMethod");
|
||||
|
||||
public string Username => _configurationSection.GetValue<string>("Username");
|
||||
|
||||
public string Password => _configurationSection.GetValue<string>("Password");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System.Net.Mail;
|
||||
|
||||
namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public interface ISmtpSettings
|
||||
@@ -6,5 +8,8 @@ namespace Umbraco.Core.Configuration
|
||||
string Host { get; }
|
||||
int Port{ get; }
|
||||
string PickupDirectoryLocation { get; }
|
||||
SmtpDeliveryMethod DeliveryMethod { get; }
|
||||
string Username { get; }
|
||||
string Password { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,6 +321,7 @@ namespace Umbraco.Core.Runtime
|
||||
composition.RegisterUnique<IEventMessagesAccessor, HybridEventMessagesAccessor>();
|
||||
composition.RegisterUnique<ITreeService, TreeService>();
|
||||
composition.RegisterUnique<ISectionService, SectionService>();
|
||||
composition.RegisterUnique<IEmailSender, EmailSender>();
|
||||
|
||||
composition.RegisterUnique<IExamineManager, ExamineManager>();
|
||||
|
||||
|
||||
@@ -185,23 +185,19 @@ namespace Umbraco.Core.Runtime
|
||||
// register ourselves (TODO: Should we put this in RegisterEssentials?)
|
||||
composition.Register<IRuntime>(_ => this, Lifetime.Singleton);
|
||||
|
||||
// determine our runtime level
|
||||
DetermineRuntimeLevel(databaseFactory, ProfilingLogger);
|
||||
|
||||
// get composers, and compose
|
||||
var composerTypes = ResolveComposerTypes(typeLoader);
|
||||
|
||||
IEnumerable<Attribute> enableDisableAttributes;
|
||||
using (ProfilingLogger.DebugDuration<CoreRuntime>("Scanning enable/disable composer attributes"))
|
||||
try
|
||||
{
|
||||
enableDisableAttributes = typeLoader.GetAssemblyAttributes(typeof(EnableComposerAttribute), typeof(DisableComposerAttribute));
|
||||
// determine our runtime level
|
||||
DetermineRuntimeLevel(databaseFactory, ProfilingLogger);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// always run composers
|
||||
RunComposers(typeLoader, composition);
|
||||
}
|
||||
|
||||
var composers = new Composers(composition, composerTypes, enableDisableAttributes, ProfilingLogger);
|
||||
composers.Compose();
|
||||
|
||||
// create the factory
|
||||
factory = composition.CreateFactory();
|
||||
// create the factory
|
||||
factory = composition.CreateFactory();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -286,6 +282,21 @@ namespace Umbraco.Core.Runtime
|
||||
};
|
||||
}
|
||||
|
||||
private void RunComposers(TypeLoader typeLoader, Composition composition)
|
||||
{
|
||||
// get composers, and compose
|
||||
var composerTypes = ResolveComposerTypes(typeLoader);
|
||||
|
||||
IEnumerable<Attribute> enableDisableAttributes;
|
||||
using (ProfilingLogger.DebugDuration<CoreRuntime>("Scanning enable/disable composer attributes"))
|
||||
{
|
||||
enableDisableAttributes = typeLoader.GetAssemblyAttributes(typeof(EnableComposerAttribute), typeof(DisableComposerAttribute));
|
||||
}
|
||||
|
||||
var composers = new Composers(composition, composerTypes, enableDisableAttributes, ProfilingLogger);
|
||||
composers.Compose();
|
||||
}
|
||||
|
||||
private bool AcquireMainDom(IMainDom mainDom, IApplicationShutdownRegistry applicationShutdownRegistry)
|
||||
{
|
||||
using (var timer = ProfilingLogger.DebugDuration<CoreRuntime>("Acquiring MainDom.", "Acquired."))
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<PackageReference Include="LightInject.Annotation" Version="1.1.0" />
|
||||
<PackageReference Include="LightInject.Microsoft.DependencyInjection" Version="3.3.0" />
|
||||
<PackageReference Include="LightInject.Microsoft.Hosting" Version="1.2.0" />
|
||||
<PackageReference Include="MailKit" Version="2.6.0" />
|
||||
<PackageReference Include="Markdown" Version="2.2.1" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.2" />
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Mail;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Composing;
|
||||
using MimeKit;
|
||||
using MimeKit.Text;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Events;
|
||||
using SmtpClient = MailKit.Net.Smtp.SmtpClient;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
@@ -21,7 +24,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
}
|
||||
|
||||
internal EmailSender(IGlobalSettings globalSettings, bool enableEvents)
|
||||
public EmailSender(IGlobalSettings globalSettings, bool enableEvents)
|
||||
{
|
||||
_globalSettings = globalSettings;
|
||||
_enableEvents = enableEvents;
|
||||
@@ -45,7 +48,17 @@ namespace Umbraco.Core
|
||||
{
|
||||
using (var client = new SmtpClient())
|
||||
{
|
||||
client.Send(message);
|
||||
|
||||
client.Connect(_globalSettings.SmtpSettings.Host, _globalSettings.SmtpSettings.Port);
|
||||
|
||||
if (!(_globalSettings.SmtpSettings.Username is null &&
|
||||
_globalSettings.SmtpSettings.Password is null))
|
||||
{
|
||||
client.Authenticate(_globalSettings.SmtpSettings.Username, _globalSettings.SmtpSettings.Password);
|
||||
}
|
||||
|
||||
client.Send(ConstructEmailMessage(message));
|
||||
client.Disconnect(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,14 +78,25 @@ namespace Umbraco.Core
|
||||
{
|
||||
using (var client = new SmtpClient())
|
||||
{
|
||||
if (client.DeliveryMethod == SmtpDeliveryMethod.Network)
|
||||
await client.ConnectAsync(_globalSettings.SmtpSettings.Host, _globalSettings.SmtpSettings.Port);
|
||||
|
||||
if (!(_globalSettings.SmtpSettings.Username is null &&
|
||||
_globalSettings.SmtpSettings.Password is null))
|
||||
{
|
||||
await client.SendMailAsync(message);
|
||||
await client.AuthenticateAsync(_globalSettings.SmtpSettings.Username, _globalSettings.SmtpSettings.Password);
|
||||
}
|
||||
|
||||
var mailMessage = ConstructEmailMessage(message);
|
||||
if (_globalSettings.SmtpSettings.DeliveryMethod == SmtpDeliveryMethod.Network)
|
||||
{
|
||||
await client.SendAsync(mailMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
client.Send(message);
|
||||
client.Send(mailMessage);
|
||||
}
|
||||
|
||||
await client.DisconnectAsync(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,7 +107,7 @@ namespace Umbraco.Core
|
||||
/// <remarks>
|
||||
/// We assume this is possible if either an event handler is registered or an smtp server is configured
|
||||
/// </remarks>
|
||||
internal static bool CanSendRequiredEmail(IGlobalSettings globalSettings) => EventHandlerRegistered || globalSettings.IsSmtpServerConfigured;
|
||||
public static bool CanSendRequiredEmail(IGlobalSettings globalSettings) => EventHandlerRegistered || globalSettings.IsSmtpServerConfigured;
|
||||
|
||||
/// <summary>
|
||||
/// returns true if an event handler has been registered
|
||||
@@ -103,5 +127,22 @@ namespace Umbraco.Core
|
||||
var handler = SendEmail;
|
||||
if (handler != null) handler(null, e);
|
||||
}
|
||||
|
||||
private MimeMessage ConstructEmailMessage(MailMessage mailMessage)
|
||||
{
|
||||
var fromEmail = mailMessage.From?.Address;
|
||||
if(string.IsNullOrEmpty(fromEmail))
|
||||
fromEmail = _globalSettings.SmtpSettings.From;
|
||||
|
||||
var messageToSend = new MimeMessage
|
||||
{
|
||||
Subject = mailMessage.Subject,
|
||||
From = { new MailboxAddress(fromEmail)},
|
||||
Body = new TextPart(mailMessage.IsBodyHtml ? TextFormat.Html : TextFormat.Plain) { Text = mailMessage.Body }
|
||||
};
|
||||
messageToSend.To.AddRange(mailMessage.To.Select(x=>new MailboxAddress(x.Address)));
|
||||
|
||||
return messageToSend;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using Umbraco.Core.Configuration;
|
||||
using System.Net.Mail;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
|
||||
namespace Umbraco.Tests.Common.Builders
|
||||
{
|
||||
@@ -16,6 +18,9 @@ namespace Umbraco.Tests.Common.Builders
|
||||
private string _host;
|
||||
private int? _port;
|
||||
private string _pickupDirectoryLocation;
|
||||
private SmtpDeliveryMethod? _deliveryMethod;
|
||||
private string _username;
|
||||
private string _password;
|
||||
|
||||
public SmtpSettingsBuilder(TParent parentBuilder) : base(parentBuilder)
|
||||
{
|
||||
@@ -33,24 +38,45 @@ namespace Umbraco.Tests.Common.Builders
|
||||
return this;
|
||||
}
|
||||
|
||||
public SmtpSettingsBuilder<TParent> WithUsername(string username)
|
||||
{
|
||||
_username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SmtpSettingsBuilder<TParent> WithPost(int port)
|
||||
{
|
||||
_port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SmtpSettingsBuilder<TParent> WithPassword(string password)
|
||||
{
|
||||
_password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SmtpSettingsBuilder<TParent> WithPickupDirectoryLocation(string pickupDirectoryLocation)
|
||||
{
|
||||
_pickupDirectoryLocation = pickupDirectoryLocation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SmtpSettingsBuilder<TParent> WithDeliveryMethod(SmtpDeliveryMethod deliveryMethod)
|
||||
{
|
||||
_deliveryMethod = deliveryMethod;
|
||||
return this;
|
||||
}
|
||||
|
||||
public override ISmtpSettings Build()
|
||||
{
|
||||
var from = _from ?? null;
|
||||
var host = _host ?? null;
|
||||
var port = _port ?? 25;
|
||||
var pickupDirectoryLocation = _pickupDirectoryLocation ?? null;
|
||||
var deliveryMethod = _deliveryMethod ?? SmtpDeliveryMethod.Network;
|
||||
var username = _username ?? null;
|
||||
var password = _password ?? null;
|
||||
|
||||
return new TestSmtpSettings()
|
||||
{
|
||||
@@ -58,6 +84,9 @@ namespace Umbraco.Tests.Common.Builders
|
||||
Host = host,
|
||||
Port = port,
|
||||
PickupDirectoryLocation = pickupDirectoryLocation,
|
||||
DeliveryMethod = deliveryMethod,
|
||||
Username = username,
|
||||
Password = password,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -67,6 +96,9 @@ namespace Umbraco.Tests.Common.Builders
|
||||
public string Host { get; set; }
|
||||
public int Port { get; set; }
|
||||
public string PickupDirectoryLocation { get; set; }
|
||||
public SmtpDeliveryMethod DeliveryMethod { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,6 +313,7 @@ namespace Umbraco.Tests.Testing
|
||||
Composition.RegisterUnique<ISectionService, SectionService>();
|
||||
|
||||
Composition.RegisterUnique<HtmlLocalLinkParser>();
|
||||
Composition.RegisterUnique<IEmailSender, EmailSender>();
|
||||
Composition.RegisterUnique<HtmlUrlParser>();
|
||||
Composition.RegisterUnique<HtmlImageSourceParser>();
|
||||
Composition.RegisterUnique<RichTextEditorPastedImages>();
|
||||
|
||||
@@ -93,7 +93,8 @@ namespace Umbraco.Tests.Web.Controllers
|
||||
Factory.GetInstance<UmbracoMapper>(),
|
||||
Factory.GetInstance<ISecuritySettings>(),
|
||||
Factory.GetInstance<IPublishedUrlProvider>(),
|
||||
Factory.GetInstance<IRequestAccessor>()
|
||||
Factory.GetInstance<IRequestAccessor>(),
|
||||
Factory.GetInstance<IEmailSender>()
|
||||
);
|
||||
return usersController;
|
||||
}
|
||||
|
||||
@@ -105,7 +105,8 @@ namespace Umbraco.Tests.Web.Controllers
|
||||
Factory.GetInstance<IImageUrlGenerator>(),
|
||||
Factory.GetInstance<IPublishedUrlProvider>(),
|
||||
Factory.GetInstance<ISecuritySettings>(),
|
||||
Factory.GetInstance<IRequestAccessor>()
|
||||
Factory.GetInstance<IRequestAccessor>(),
|
||||
Factory.GetInstance<IEmailSender>()
|
||||
|
||||
);
|
||||
return usersController;
|
||||
@@ -179,7 +180,8 @@ namespace Umbraco.Tests.Web.Controllers
|
||||
Factory.GetInstance<IImageUrlGenerator>(),
|
||||
Factory.GetInstance<IPublishedUrlProvider>(),
|
||||
Factory.GetInstance<ISecuritySettings>(),
|
||||
Factory.GetInstance<IRequestAccessor>()
|
||||
Factory.GetInstance<IRequestAccessor>(),
|
||||
Factory.GetInstance<IEmailSender>()
|
||||
);
|
||||
return usersController;
|
||||
}
|
||||
@@ -223,7 +225,8 @@ namespace Umbraco.Tests.Web.Controllers
|
||||
Factory.GetInstance<IImageUrlGenerator>(),
|
||||
Factory.GetInstance<IPublishedUrlProvider>(),
|
||||
Factory.GetInstance<ISecuritySettings>(),
|
||||
Factory.GetInstance<IRequestAccessor>()
|
||||
Factory.GetInstance<IRequestAccessor>(),
|
||||
Factory.GetInstance<IEmailSender>()
|
||||
);
|
||||
return usersController;
|
||||
}
|
||||
@@ -302,7 +305,8 @@ namespace Umbraco.Tests.Web.Controllers
|
||||
Factory.GetInstance<IImageUrlGenerator>(),
|
||||
Factory.GetInstance<IPublishedUrlProvider>(),
|
||||
Factory.GetInstance<ISecuritySettings>(),
|
||||
Factory.GetInstance<IRequestAccessor>()
|
||||
Factory.GetInstance<IRequestAccessor>(),
|
||||
Factory.GetInstance<IEmailSender>()
|
||||
);
|
||||
return usersController;
|
||||
}
|
||||
@@ -493,7 +497,8 @@ namespace Umbraco.Tests.Web.Controllers
|
||||
Factory.GetInstance<IImageUrlGenerator>(),
|
||||
Factory.GetInstance<IPublishedUrlProvider>(),
|
||||
Factory.GetInstance<ISecuritySettings>(),
|
||||
Factory.GetInstance<IRequestAccessor>());
|
||||
Factory.GetInstance<IRequestAccessor>(),
|
||||
Factory.GetInstance<IEmailSender>());
|
||||
|
||||
var mockOwinContext = new Mock<IOwinContext>();
|
||||
var mockUserManagerMarker = new Mock<IBackOfficeUserManagerMarker>();
|
||||
|
||||
@@ -27,8 +27,6 @@ namespace Umbraco.Extensions
|
||||
return runtime.State.Level > RuntimeLevel.BootFailed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Start Umbraco
|
||||
/// </summary>
|
||||
@@ -38,27 +36,20 @@ namespace Umbraco.Extensions
|
||||
{
|
||||
if (app == null) throw new ArgumentNullException(nameof(app));
|
||||
|
||||
if (app.UmbracoCanBoot())
|
||||
{
|
||||
var runtime = app.ApplicationServices.GetRequiredService<IRuntime>();
|
||||
if (!app.UmbracoCanBoot()) return app;
|
||||
|
||||
// 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);
|
||||
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
|
||||
// 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 :)
|
||||
|
||||
}
|
||||
// Start the runtime!
|
||||
runtime.Start();
|
||||
|
||||
return app;
|
||||
}
|
||||
@@ -73,13 +64,24 @@ namespace Umbraco.Extensions
|
||||
{
|
||||
if (app == null) throw new ArgumentNullException(nameof(app));
|
||||
|
||||
if (!app.UmbracoCanBoot()) return app;
|
||||
if (!app.UmbracoCanBoot())
|
||||
{
|
||||
app.UseMiddleware<BootFailedMiddleware>();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseMiddleware<UmbracoRequestMiddleware>();
|
||||
app.UseMiddleware<MiniProfilerMiddleware>();
|
||||
}
|
||||
|
||||
app.UseMiddleware<UmbracoRequestMiddleware>();
|
||||
app.UseMiddleware<MiniProfilerMiddleware>();
|
||||
return app;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds request based serilog enrichers to the LogContext for each request
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseUmbracoRequestLogging(this IApplicationBuilder app)
|
||||
{
|
||||
if (app == null) throw new ArgumentNullException(nameof(app));
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace Umbraco.Extensions
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseUmbracoInstaller(this IApplicationBuilder app)
|
||||
{
|
||||
if (!app.UmbracoCanBoot()) return app;
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
var installerRoutes = app.ApplicationServices.GetRequiredService<InstallAreaRoutes>();
|
||||
|
||||
@@ -34,10 +34,6 @@ 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>());
|
||||
|
||||
|
||||
@@ -92,6 +92,10 @@ namespace Umbraco.Web.Common.Install
|
||||
return View();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to perform the redirect to the installer when the runtime level is <see cref="RuntimeLevel.Install"/> or <see cref="RuntimeLevel.Upgrade"/>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public ActionResult Redirect()
|
||||
{
|
||||
|
||||
34
src/Umbraco.Web.Common/Middleware/BootFailedMiddleware.cs
Normal file
34
src/Umbraco.Web.Common/Middleware/BootFailedMiddleware.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Exceptions;
|
||||
|
||||
namespace Umbraco.Web.Common.Middleware
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes when Umbraco booting fails in order to show the problem
|
||||
/// </summary>
|
||||
public class BootFailedMiddleware : IMiddleware
|
||||
{
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
|
||||
public BootFailedMiddleware(IRuntimeState runtimeState)
|
||||
{
|
||||
_runtimeState = runtimeState;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
|
||||
{
|
||||
if (_runtimeState.Level == RuntimeLevel.BootFailed)
|
||||
{
|
||||
// short circuit
|
||||
BootFailedException.Rethrow(_runtimeState.BootFailedException);
|
||||
}
|
||||
else
|
||||
{
|
||||
await next(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,9 @@ using Umbraco.Core.Logging.Serilog.Enrichers;
|
||||
|
||||
namespace Umbraco.Web.Common.Middleware
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds request based serilog enrichers to the LogContext for each request
|
||||
/// </summary>
|
||||
public class UmbracoRequestLoggingMiddleware : IMiddleware
|
||||
{
|
||||
private readonly HttpSessionIdEnricher _sessionIdEnricher;
|
||||
|
||||
@@ -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<UmbracoRequestMiddleware>("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<UmbracoRequestMiddleware>(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<UmbracoRequestMiddleware>("End Request [{HttpRequestId}]: {RequestUrl} ({RequestDuration}ms)", httpRequestId, requestUri, DateTime.Now.Subtract(umbracoContextReference.UmbracoContext.ObjectCreated).TotalMilliseconds);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
DisposeRequestCacheItems(_logger, _requestCache, requestUri);
|
||||
}
|
||||
finally
|
||||
{
|
||||
umbracoContextReference.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Any object that is in the HttpContext.Items collection that is IDisposable will get disposed on the end of the request
|
||||
/// </summary>
|
||||
/// <param name="http"></param>
|
||||
/// <param name="requestCache"></param>
|
||||
/// <param name="requestUri"></param>
|
||||
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<string>();
|
||||
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<UmbracoRequestMiddleware>("Could not dispose item with key " + k, ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
k.DisposeIfDisposable();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error<UmbracoRequestMiddleware>("Could not dispose item key " + k, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Web.Common.Middleware;
|
||||
|
||||
namespace Umbraco.Web.Common.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes if the boot fails to ensure critical services are registered
|
||||
/// </summary>
|
||||
[RuntimeLevel(MinLevel = RuntimeLevel.BootFailed)]
|
||||
public class AspNetCoreBootFailedComposer : IComposer
|
||||
{
|
||||
public void Compose(Composition composition)
|
||||
{
|
||||
composition.RegisterUnique<BootFailedMiddleware>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,13 @@ using Umbraco.Web.Common.Install;
|
||||
using Umbraco.Extensions;
|
||||
using System.Linq;
|
||||
using Umbraco.Web.Common.Controllers;
|
||||
using System;
|
||||
using Umbraco.Web.Common.Middleware;
|
||||
using Umbraco.Web.Common.ModelBinding;
|
||||
|
||||
namespace Umbraco.Web.Common.Runtime
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Adds/replaces AspNetCore specific services
|
||||
/// </summary>
|
||||
@@ -77,6 +81,11 @@ namespace Umbraco.Web.Common.Runtime
|
||||
|
||||
composition.RegisterUnique<InstallAreaRoutes>();
|
||||
|
||||
composition.RegisterUnique<UmbracoRequestLoggingMiddleware>();
|
||||
composition.RegisterUnique<UmbracoRequestMiddleware>();
|
||||
composition.RegisterUnique<BootFailedMiddleware>();
|
||||
|
||||
composition.RegisterUnique<UmbracoJsonModelBinder>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Mail;
|
||||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
@@ -48,6 +49,7 @@ namespace Umbraco.Web.Editors
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
private readonly ISecuritySettings _securitySettings;
|
||||
private readonly IRequestAccessor _requestAccessor;
|
||||
private readonly IEmailSender _emailSender;
|
||||
|
||||
public AuthenticationController(
|
||||
IUserPasswordConfiguration passwordConfiguration,
|
||||
@@ -62,7 +64,8 @@ namespace Umbraco.Web.Editors
|
||||
UmbracoMapper umbracoMapper,
|
||||
ISecuritySettings securitySettings,
|
||||
IPublishedUrlProvider publishedUrlProvider,
|
||||
IRequestAccessor requestAccessor)
|
||||
IRequestAccessor requestAccessor,
|
||||
IEmailSender emailSender)
|
||||
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoMapper, publishedUrlProvider)
|
||||
{
|
||||
_passwordConfiguration = passwordConfiguration ?? throw new ArgumentNullException(nameof(passwordConfiguration));
|
||||
@@ -70,6 +73,7 @@ namespace Umbraco.Web.Editors
|
||||
_runtimeState = runtimeState ?? throw new ArgumentNullException(nameof(runtimeState));
|
||||
_securitySettings = securitySettings ?? throw new ArgumentNullException(nameof(securitySettings));
|
||||
_requestAccessor = requestAccessor ?? throw new ArgumentNullException(nameof(securitySettings));
|
||||
_emailSender = emailSender;
|
||||
}
|
||||
|
||||
protected BackOfficeUserManager<BackOfficeIdentityUser> UserManager => _userManager
|
||||
@@ -331,12 +335,19 @@ namespace Umbraco.Web.Editors
|
||||
UmbracoUserExtensions.GetUserCulture(identityUser.Culture, Services.TextService, GlobalSettings),
|
||||
new[] { identityUser.UserName, callbackUrl });
|
||||
|
||||
// TODO: Port email service to ASP.NET Core
|
||||
/*await UserManager.SendEmailAsync(identityUser.Id,
|
||||
Services.TextService.Localize("login/resetPasswordEmailCopySubject",
|
||||
// Ensure the culture of the found user is used for the email!
|
||||
UmbracoUserExtensions.GetUserCulture(identityUser.Culture, Services.TextService, GlobalSettings)),
|
||||
message);*/
|
||||
var subject = Services.TextService.Localize("login/resetPasswordEmailCopySubject",
|
||||
// Ensure the culture of the found user is used for the email!
|
||||
UmbracoUserExtensions.GetUserCulture(identityUser.Culture, Services.TextService, GlobalSettings));
|
||||
|
||||
var mailMessage = new MailMessage()
|
||||
{
|
||||
Subject = subject,
|
||||
Body = message,
|
||||
IsBodyHtml = true,
|
||||
To = { user.Email}
|
||||
};
|
||||
|
||||
await _emailSender.SendAsync(mailMessage);
|
||||
|
||||
UserManager.RaiseForgotPasswordRequestedEvent(user.Id);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Mail;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
@@ -53,6 +54,7 @@ namespace Umbraco.Web.Editors
|
||||
private readonly IImageUrlGenerator _imageUrlGenerator;
|
||||
private readonly ISecuritySettings _securitySettings;
|
||||
private readonly IRequestAccessor _requestAccessor;
|
||||
private readonly IEmailSender _emailSender;
|
||||
|
||||
public UsersController(
|
||||
IGlobalSettings globalSettings,
|
||||
@@ -70,7 +72,8 @@ namespace Umbraco.Web.Editors
|
||||
IImageUrlGenerator imageUrlGenerator,
|
||||
IPublishedUrlProvider publishedUrlProvider,
|
||||
ISecuritySettings securitySettings,
|
||||
IRequestAccessor requestAccessor)
|
||||
IRequestAccessor requestAccessor,
|
||||
IEmailSender emailSender)
|
||||
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider)
|
||||
{
|
||||
_mediaFileSystem = mediaFileSystem;
|
||||
@@ -80,6 +83,7 @@ namespace Umbraco.Web.Editors
|
||||
_imageUrlGenerator = imageUrlGenerator;
|
||||
_securitySettings = securitySettings;
|
||||
_requestAccessor = requestAccessor;
|
||||
_emailSender = emailSender;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -503,17 +507,15 @@ namespace Umbraco.Web.Editors
|
||||
UmbracoUserExtensions.GetUserCulture(to.Language, Services.TextService, GlobalSettings),
|
||||
new[] { userDisplay.Name, from, message, inviteUri.ToString(), fromEmail });
|
||||
|
||||
// TODO: Port email service to ASP.NET Core
|
||||
/*await UserManager.EmailService.SendAsync(
|
||||
//send the special UmbracoEmailMessage which configures it's own sender
|
||||
//to allow for events to handle sending the message if no smtp is configured
|
||||
new UmbracoEmailMessage(new EmailSender(GlobalSettings, true))
|
||||
{
|
||||
Body = emailBody,
|
||||
Destination = userDisplay.Email,
|
||||
Subject = emailSubject
|
||||
});*/
|
||||
var mailMessage = new MailMessage()
|
||||
{
|
||||
Subject = emailSubject,
|
||||
Body = emailBody,
|
||||
IsBodyHtml = true,
|
||||
To = { to.Email}
|
||||
};
|
||||
|
||||
await _emailSender.SendAsync(mailMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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<UmbracoModule>(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
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Any object that is in the HttpContext.Items collection that is IDisposable will get disposed on the end of the request
|
||||
/// </summary>
|
||||
/// <param name="http"></param>
|
||||
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<string>();
|
||||
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<UmbracoModule>("Could not dispose item with key " + k, ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
k.DisposeIfDisposable();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error<UmbracoModule>("Could not dispose item key " + k, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region IHttpModule
|
||||
@@ -361,55 +308,13 @@ namespace Umbraco.Web
|
||||
/// <param name="app"></param>
|
||||
public void Init(HttpApplication app)
|
||||
{
|
||||
if (_runtime.Level == RuntimeLevel.BootFailed)
|
||||
{
|
||||
// there's nothing we can do really
|
||||
app.BeginRequest += (sender, args) =>
|
||||
{
|
||||
// would love to avoid throwing, and instead display a customized Umbraco 500
|
||||
// page - however if we don't throw here, something else might go wrong, and
|
||||
// it's this later exception that would be reported. could not figure out how
|
||||
// to prevent it, either with httpContext.Response.End() or .ApplicationInstance
|
||||
// .CompleteRequest()
|
||||
|
||||
// also, if something goes wrong with our DI setup, the logging subsystem may
|
||||
// not even kick in, so here we try to give as much detail as possible
|
||||
|
||||
BootFailedException.Rethrow(Current.RuntimeState.BootFailedException);
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
app.BeginRequest += (sender, e) =>
|
||||
{
|
||||
var httpContext = ((HttpApplication) sender).Context;
|
||||
|
||||
LogHttpRequest.TryGetCurrentHttpRequestId(out var httpRequestId, _requestCache);
|
||||
|
||||
_logger.Verbose<UmbracoModule>("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;
|
||||
@@ -427,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<UmbracoModule>("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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user