Files
Umbraco-CMS/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoApplicationBuilder.cs
Vitor Rodrigues 7d9bb8f595 Exposed media file provider configuration method (#13294)
This is required for consumers that intend to use WithCustomMiddleware instead of WithMiddleware, as otherwise they are forced to re-implement this code
2023-01-04 10:23:16 +01:00

147 lines
4.9 KiB
C#

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Services;
using Umbraco.Extensions;
namespace Umbraco.Cms.Web.Common.ApplicationBuilder;
/// <summary>
/// A builder used to enable middleware and endpoints required for Umbraco to operate.
/// </summary>
/// <remarks>
/// This helps to ensure that everything is registered in the correct order.
/// </remarks>
public class UmbracoApplicationBuilder : IUmbracoApplicationBuilder, IUmbracoEndpointBuilder,
IUmbracoApplicationBuilderContext
{
private readonly IOptions<UmbracoPipelineOptions> _umbracoPipelineStartupOptions;
public UmbracoApplicationBuilder(IApplicationBuilder appBuilder)
{
AppBuilder = appBuilder ?? throw new ArgumentNullException(nameof(appBuilder));
ApplicationServices = appBuilder.ApplicationServices;
RuntimeState = appBuilder.ApplicationServices.GetRequiredService<IRuntimeState>();
_umbracoPipelineStartupOptions = ApplicationServices.GetRequiredService<IOptions<UmbracoPipelineOptions>>();
}
public IServiceProvider ApplicationServices { get; }
public IRuntimeState RuntimeState { get; }
public IApplicationBuilder AppBuilder { get; }
/// <inheritdoc />
public IUmbracoEndpointBuilder WithCustomMiddleware(
Action<IUmbracoApplicationBuilderContext> configureUmbracoMiddleware)
{
if (configureUmbracoMiddleware is null)
{
throw new ArgumentNullException(nameof(configureUmbracoMiddleware));
}
configureUmbracoMiddleware(this);
return this;
}
/// <inheritdoc />
public IUmbracoEndpointBuilder WithMiddleware(Action<IUmbracoApplicationBuilderContext> configureUmbracoMiddleware)
{
if (configureUmbracoMiddleware is null)
{
throw new ArgumentNullException(nameof(configureUmbracoMiddleware));
}
RunPrePipeline();
RegisterDefaultRequiredMiddleware();
RunPostPipeline();
configureUmbracoMiddleware(this);
return this;
}
/// <summary>
/// Registers the default required middleware to run Umbraco.
/// </summary>
public void RegisterDefaultRequiredMiddleware()
{
UseUmbracoCoreMiddleware();
AppBuilder.UseUmbracoMediaFileProvider();
AppBuilder.UseStaticFiles();
AppBuilder.UseUmbracoPluginsStaticFiles();
// UseRouting adds endpoint routing middleware, this means that middlewares registered after this one
// will execute after endpoint routing. The ordering of everything is quite important here, see
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-5.0
// where we need to have UseAuthentication and UseAuthorization proceeding this call but before
// endpoints are defined.
AppBuilder.UseRouting();
AppBuilder.UseAuthentication();
AppBuilder.UseAuthorization();
// This must come after auth because the culture is based on the auth'd user
AppBuilder.UseRequestLocalization();
// Must be called after UseRouting and before UseEndpoints
AppBuilder.UseSession();
// DO NOT PUT ANY UseEndpoints declarations here!! Those must all come very last in the pipeline,
// endpoints are terminating middleware. All of our endpoints are declared in ext of IUmbracoApplicationBuilder
}
public void UseUmbracoCoreMiddleware()
{
AppBuilder.UseUmbracoCore();
AppBuilder.UseUmbracoRequestLogging();
// We need to add this before UseRouting so that the UmbracoContext and other middlewares are executed
// before endpoint routing middleware.
AppBuilder.UseUmbracoRouting();
}
public void RunPrePipeline()
{
foreach (IUmbracoPipelineFilter filter in _umbracoPipelineStartupOptions.Value.PipelineFilters)
{
filter.OnPrePipeline(AppBuilder);
}
}
public void RunPostPipeline()
{
foreach (IUmbracoPipelineFilter filter in _umbracoPipelineStartupOptions.Value.PipelineFilters)
{
filter.OnPostPipeline(AppBuilder);
}
}
/// <inheritdoc />
public void WithEndpoints(Action<IUmbracoEndpointBuilderContext> configureUmbraco)
{
RunPreEndpointsPipeline();
AppBuilder.UseEndpoints(endpoints =>
{
var umbAppBuilder =
(IUmbracoEndpointBuilderContext)ActivatorUtilities.CreateInstance<UmbracoEndpointBuilder>(
ApplicationServices, AppBuilder, endpoints);
configureUmbraco(umbAppBuilder);
});
}
private void RunPreEndpointsPipeline()
{
foreach (IUmbracoPipelineFilter filter in _umbracoPipelineStartupOptions.Value.PipelineFilters)
{
filter.OnEndpoints(AppBuilder);
}
}
}