diff --git a/.gitignore b/.gitignore
index d8c3f27d5a..99c21bd287 100644
--- a/.gitignore
+++ b/.gitignore
@@ -177,3 +177,5 @@ build/temp/
/src/Umbraco.Web.UI.NetCore/wwwroot/Umbraco/views/*
/src/Umbraco.Web.UI.NetCore/wwwroot/App_Data/TEMP/*
/src/Umbraco.Web.UI.NetCore/App_Data/Logs/*
+/src/Umbraco.Web.UI.NetCore/App_Data/TEMP/TypesCache/*
+/src/Umbraco.Web.UI.NetCore/App_Data/TEMP/*
diff --git a/src/Umbraco.Web.Common/ApplicationModels/UmbracoApiBehaviorApplicationModelProvider.cs b/src/Umbraco.Web.Common/ApplicationModels/UmbracoApiBehaviorApplicationModelProvider.cs
new file mode 100644
index 0000000000..54cb650ce0
--- /dev/null
+++ b/src/Umbraco.Web.Common/ApplicationModels/UmbracoApiBehaviorApplicationModelProvider.cs
@@ -0,0 +1,93 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.ApplicationModels;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using System.Collections.Generic;
+using System.Linq;
+using Umbraco.Core;
+using Umbraco.Web.Common.Attributes;
+using Umbraco.Web.Common.ModelBinding;
+
+namespace Umbraco.Web.Common.ApplicationModels
+{
+ public class NewtonsoftJsonModelBinderConvention : IActionModelConvention
+ {
+ public void Apply(ActionModel action)
+ {
+ foreach(var p in action.Parameters)
+ {
+ if (p.BindingInfo?.BindingSource == BindingSource.Body)
+ {
+ p.BindingInfo.BinderType = typeof(UmbracoJsonModelBinder);
+ }
+ }
+ }
+ }
+
+ ///
+ /// A custom application model provider for Umbraco controllers
+ ///
+ ///
+ ///
+ /// Conventions will be applied to controllers attributed with
+ ///
+ ///
+ /// This is nearly a copy of aspnetcore's ApiBehaviorApplicationModelProvider which supplies a convention for the
+ /// [ApiController] attribute, however that convention is too strict for our purposes so we will have our own.
+ ///
+ ///
+ public class UmbracoApiBehaviorApplicationModelProvider : IApplicationModelProvider
+ {
+ public UmbracoApiBehaviorApplicationModelProvider(IModelMetadataProvider modelMetadataProvider)
+ {
+ // see see https://docs.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-3.1#apicontroller-attribute
+ // for what these things actually do
+ // NOTE: we don't have attribute routing requirements and we cannot use ApiVisibilityConvention without attribute routing
+
+ ActionModelConventions = new List()
+ {
+ new ClientErrorResultFilterConvention(), // TODO: Need to determine exactly how this affects errors
+ new InvalidModelStateFilterConvention(), // automatically 400 responses if ModelState is invalid before hitting the controller
+ new ConsumesConstraintForFormFileParameterConvention(), // If an controller accepts files, it must accept multipart/form-data.
+ new InferParameterBindingInfoConvention(modelMetadataProvider), // no need for [FromBody] everywhere, A complex type parameter is assigned to FromBody
+
+ new NewtonsoftJsonModelBinderConvention()
+ };
+
+ // TODO: Need to determine exactly how this affects errors
+ var defaultErrorType = typeof(ProblemDetails);
+ var defaultErrorTypeAttribute = new ProducesErrorResponseTypeAttribute(defaultErrorType);
+ ActionModelConventions.Add(new ApiConventionApplicationModelConvention(defaultErrorTypeAttribute));
+ }
+
+ ///
+ /// Will execute after
+ ///
+ public int Order => 0;
+
+ public List ActionModelConventions { get; }
+
+ public void OnProvidersExecuted(ApplicationModelProviderContext context)
+ {
+ }
+
+ public void OnProvidersExecuting(ApplicationModelProviderContext context)
+ {
+ foreach (var controller in context.Result.Controllers)
+ {
+ if (!IsUmbracoApiController(controller))
+ continue;
+
+ foreach (var action in controller.Actions)
+ {
+ foreach (var convention in ActionModelConventions)
+ {
+ convention.Apply(action);
+ }
+ }
+
+ }
+ }
+
+ private bool IsUmbracoApiController(ControllerModel controller) => controller.Attributes.OfType().Any();
+ }
+}
diff --git a/src/Umbraco.Web.Common/Attributes/UmbracoApiControllerAttribute.cs b/src/Umbraco.Web.Common/Attributes/UmbracoApiControllerAttribute.cs
new file mode 100644
index 0000000000..a3ffc3d9e9
--- /dev/null
+++ b/src/Umbraco.Web.Common/Attributes/UmbracoApiControllerAttribute.cs
@@ -0,0 +1,13 @@
+using System;
+using Umbraco.Web.Common.ApplicationModels;
+
+namespace Umbraco.Web.Common.Attributes
+{
+ ///
+ /// When present on a controller then conventions will apply
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
+ public sealed class UmbracoApiControllerAttribute : Attribute
+ {
+ }
+}
diff --git a/src/Umbraco.Web.Common/Controllers/UmbracoApiControllerBase.cs b/src/Umbraco.Web.Common/Controllers/UmbracoApiControllerBase.cs
index 4a0bff7ffb..01300d1fa5 100644
--- a/src/Umbraco.Web.Common/Controllers/UmbracoApiControllerBase.cs
+++ b/src/Umbraco.Web.Common/Controllers/UmbracoApiControllerBase.cs
@@ -1,26 +1,26 @@
-using System;
-using Microsoft.AspNetCore.Mvc;
-using Umbraco.Core;
-using Umbraco.Core.Cache;
-using Umbraco.Core.Configuration;
-using Umbraco.Core.Logging;
-using Umbraco.Core.Mapping;
-using Umbraco.Core.Persistence;
-using Umbraco.Core.Services;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Umbraco.Web.Common.Filters;
using Umbraco.Web.Features;
-using Umbraco.Web.Routing;
-using Umbraco.Web.Security;
using Umbraco.Web.WebApi.Filters;
+using Umbraco.Web.Common.Attributes;
namespace Umbraco.Web.Common.Controllers
{
///
/// Provides a base class for Umbraco API controllers.
///
- /// These controllers are NOT auto-routed.
+ ///
+ /// These controllers are NOT auto-routed.
+ /// The base class is which are netcore API controllers without any view support
+ ///
[FeatureAuthorize]
- public abstract class UmbracoApiControllerBase : Controller, IUmbracoFeature
+ [TypeFilter(typeof(HttpResponseExceptionFilter))]
+ [UmbracoApiController]
+ public abstract class UmbracoApiControllerBase : ControllerBase, IUmbracoFeature
{
-
+ public UmbracoApiControllerBase()
+ {
+ }
}
}
diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoCommonApplicationBuilderExtensions.cs b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs
similarity index 62%
rename from src/Umbraco.Web.Common/Extensions/UmbracoCommonApplicationBuilderExtensions.cs
rename to src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs
index 8386a1d8fe..47cee99264 100644
--- a/src/Umbraco.Web.Common/Extensions/UmbracoCommonApplicationBuilderExtensions.cs
+++ b/src/Umbraco.Web.Common/Extensions/ApplicationBuilderExtensions.cs
@@ -7,8 +7,13 @@ using Umbraco.Web.Common.Middleware;
namespace Umbraco.Extensions
{
- public static class UmbracoCommonApplicationBuilderExtensions
+ public static class ApplicationBuilderExtensions
{
+ ///
+ /// Returns true if Umbraco is greater than
+ ///
+ ///
+ ///
public static bool UmbracoCanBoot(this IApplicationBuilder app)
{
var runtime = app.ApplicationServices.GetRequiredService();
@@ -16,8 +21,13 @@ namespace Umbraco.Extensions
return runtime.State.Level > RuntimeLevel.BootFailed;
}
+ ///
+ /// Enables middlewares required to run Umbraco
+ ///
+ ///
+ ///
// TODO: Could be internal or part of another call - this is a required system so should't be 'opt-in'
- public static IApplicationBuilder UseUmbracoRequestLifetime(this IApplicationBuilder app)
+ public static IApplicationBuilder UseUmbracoRouting(this IApplicationBuilder app)
{
if (app == null) throw new ArgumentNullException(nameof(app));
diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs
index 256bc1a78c..5078fa5f22 100644
--- a/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs
+++ b/src/Umbraco.Web.Common/Extensions/UmbracoCoreServiceCollectionExtensions.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections;
-using System.Collections.Generic;
using System.Data.Common;
using System.Data.SqlClient;
using System.IO;
@@ -13,8 +12,6 @@ using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Extensions.Hosting;
using Serilog.Extensions.Logging;
-using Smidge;
-using Smidge.Nuglify;
using Umbraco.Composing;
using Umbraco.Configuration;
using Umbraco.Core;
@@ -28,12 +25,19 @@ using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Runtime;
using Umbraco.Web.Common.AspNetCore;
-using Umbraco.Web.Common.Runtime.Profiler;
+using Umbraco.Web.Common.Profiler;
namespace Umbraco.Extensions
{
+
+
public static class UmbracoCoreServiceCollectionExtensions
{
+ ///
+ /// Adds SqlCe support for Umbraco
+ ///
+ ///
+ ///
public static IServiceCollection AddUmbracoSqlCeSupport(this IServiceCollection services)
{
try
@@ -60,7 +64,7 @@ namespace Umbraco.Extensions
var sqlCe = sqlCeAssembly.GetType("System.Data.SqlServerCe.SqlCeProviderFactory");
if (!(sqlCe is null))
{
- DbProviderFactories.RegisterFactory(Core.Constants.DbProviderNames.SqlCe, sqlCe );
+ DbProviderFactories.RegisterFactory(Core.Constants.DbProviderNames.SqlCe, sqlCe);
}
}
}
@@ -72,6 +76,11 @@ namespace Umbraco.Extensions
return services;
}
+ ///
+ /// Adds Sql Server support for Umbraco
+ ///
+ ///
+ ///
public static IServiceCollection AddUmbracoSqlServerSupport(this IServiceCollection services)
{
DbProviderFactories.RegisterFactory(Core.Constants.DbProviderNames.SqlServer, SqlClientFactory.Instance);
@@ -102,7 +111,6 @@ namespace Umbraco.Extensions
return services;
}
-
///
/// Adds the Umbraco Back Core requirements
///
@@ -111,7 +119,7 @@ namespace Umbraco.Extensions
///
public static IServiceCollection AddUmbracoCore(this IServiceCollection services, IWebHostEnvironment webHostEnvironment)
{
- return services.AddUmbracoCore(webHostEnvironment,out _);
+ return services.AddUmbracoCore(webHostEnvironment, out _);
}
///
@@ -198,7 +206,7 @@ namespace Umbraco.Extensions
configs,
webHostEnvironment,
loggingConfiguration,
- out var logger, out var ioHelper, out var hostingEnvironment, out var backOfficeInfo, out var profiler);
+ out var logger, out var ioHelper, out var hostingEnvironment, out var backOfficeInfo, out var profiler);
var globalSettings = configs.Global();
var umbracoVersion = new UmbracoVersion(globalSettings);
@@ -219,8 +227,7 @@ namespace Umbraco.Extensions
factory = coreRuntime.Configure(container);
return services;
- }
-
+ }
private static ITypeFinder CreateTypeFinder(Core.Logging.ILogger logger, IProfiler profiler, IWebHostEnvironment webHostEnvironment, Assembly entryAssembly, ITypeFinderSettings typeFinderSettings)
{
@@ -322,15 +329,6 @@ namespace Umbraco.Extensions
return logger;
}
- public static IServiceCollection AddUmbracoRuntimeMinifier(this IServiceCollection services,
- IConfiguration configuration)
- {
- services.AddSmidge(configuration.GetSection(Core.Constants.Configuration.ConfigRuntimeMinification));
- services.AddSmidgeNuglify();
-
- return services;
- }
-
private static IProfiler GetWebProfiler(Umbraco.Core.Hosting.IHostingEnvironment hostingEnvironment)
{
// create and start asap to profile boot
@@ -346,6 +344,7 @@ namespace Umbraco.Extensions
return webProfiler;
}
+
private class AspNetCoreBootPermissionsChecker : IUmbracoBootPermissionChecker
{
public void ThrowIfNotPermissions()
@@ -354,7 +353,6 @@ namespace Umbraco.Extensions
}
}
-
}
}
diff --git a/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs b/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs
new file mode 100644
index 0000000000..0278630be8
--- /dev/null
+++ b/src/Umbraco.Web.Common/Extensions/UmbracoWebServiceCollectionExtensions.cs
@@ -0,0 +1,151 @@
+using System.Buffers;
+using System.Collections.Generic;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.ApplicationModels;
+using Microsoft.AspNetCore.Mvc.Infrastructure;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.ObjectPool;
+using Microsoft.Extensions.Options;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.Web.Caching;
+using SixLabors.ImageSharp.Web.Commands;
+using SixLabors.ImageSharp.Web.DependencyInjection;
+using SixLabors.ImageSharp.Web.Processors;
+using SixLabors.ImageSharp.Web.Providers;
+using Smidge;
+using Smidge.Nuglify;
+using Umbraco.Core;
+using Umbraco.Core.Configuration;
+using Umbraco.Web.Common.ApplicationModels;
+using Umbraco.Web.Common.ModelBinding;
+
+namespace Umbraco.Extensions
+{
+ public static class UmbracoWebServiceCollectionExtensions
+ {
+ ///
+ /// Registers the web components needed for Umbraco
+ ///
+ ///
+ ///
+ public static IServiceCollection AddUmbracoWebComponents(this IServiceCollection services)
+ {
+ services.TryAddSingleton();
+ services.TryAddSingleton();
+ services.TryAddSingleton();
+ //services.ConfigureOptions();
+ services.TryAddEnumerable(ServiceDescriptor.Transient());
+
+ // TODO: We need to avoid this, surely there's a way? See ContainerTests.BuildServiceProvider_Before_Host_Is_Configured
+ var serviceProvider = services.BuildServiceProvider();
+ var configs = serviceProvider.GetService();
+ var imagingSettings = configs.Imaging();
+ services.AddUmbracoImageSharp(imagingSettings);
+
+ return services;
+ }
+
+ ///
+ /// Adds Image Sharp with Umbraco settings
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection AddUmbracoImageSharp(this IServiceCollection services, IImagingSettings imagingSettings)
+ {
+ services.AddImageSharpCore(
+ options =>
+ {
+ options.Configuration = SixLabors.ImageSharp.Configuration.Default;
+ options.MaxBrowserCacheDays = imagingSettings.MaxBrowserCacheDays;
+ options.MaxCacheDays = imagingSettings.MaxCacheDays;
+ options.CachedNameLength = imagingSettings.CachedNameLength;
+ options.OnParseCommands = context =>
+ {
+ RemoveIntParamenterIfValueGreatherThen(context.Commands, ResizeWebProcessor.Width, imagingSettings.MaxResizeWidth);
+ RemoveIntParamenterIfValueGreatherThen(context.Commands, ResizeWebProcessor.Height, imagingSettings.MaxResizeHeight);
+ };
+ options.OnBeforeSave = _ => { };
+ options.OnProcessed = _ => { };
+ options.OnPrepareResponse = _ => { };
+ })
+ .SetRequestParser()
+ .SetMemoryAllocator(provider => ArrayPoolMemoryAllocator.CreateWithMinimalPooling())
+ .Configure(options =>
+ {
+ options.CacheFolder = imagingSettings.CacheFolder;
+ })
+ .SetCache()
+ .SetCacheHash()
+ .AddProvider()
+ .AddProcessor()
+ .AddProcessor()
+ .AddProcessor();
+
+ return services;
+ }
+
+ ///
+ /// Adds the Umbraco runtime minifier
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection AddUmbracoRuntimeMinifier(this IServiceCollection services,
+ IConfiguration configuration)
+ {
+ services.AddSmidge(configuration.GetSection(Core.Constants.Configuration.ConfigRuntimeMinification));
+ services.AddSmidgeNuglify();
+
+ return services;
+ }
+
+ private static void RemoveIntParamenterIfValueGreatherThen(IDictionary commands, string parameter, int maxValue)
+ {
+ if (commands.TryGetValue(parameter, out var command))
+ {
+ if (int.TryParse(command, out var i))
+ {
+ if (i > maxValue)
+ {
+ commands.Remove(parameter);
+ }
+ }
+ }
+ }
+
+ ///
+ /// Options for configuring MVC
+ ///
+ ///
+ /// We generally don't want to change the global MVC settings since we want to be unobtrusive as possible but some
+ /// global mods are needed - so long as they don't interfere with normal user usages of MVC.
+ ///
+ private class UmbracoMvcConfigureOptions : IConfigureOptions
+ {
+ private readonly IHttpRequestStreamReaderFactory _readerFactory;
+ private readonly ILoggerFactory _logger;
+ private readonly ArrayPool _arrayPool;
+ private readonly ObjectPoolProvider _objectPoolProvider;
+
+ public UmbracoMvcConfigureOptions(IHttpRequestStreamReaderFactory readerFactory, ILoggerFactory logger, ArrayPool arrayPool, ObjectPoolProvider objectPoolProvider)
+ {
+ _readerFactory = readerFactory;
+ _logger = logger;
+ _arrayPool = arrayPool;
+ _objectPoolProvider = objectPoolProvider;
+ }
+
+ public void Configure(MvcOptions options)
+ {
+ options.ModelBinderProviders.Insert(0, new UmbracoJsonModelBinderProvider(_readerFactory, _logger, _arrayPool, _objectPoolProvider));
+ }
+ }
+
+
+ }
+
+}
diff --git a/src/Umbraco.Web.Common/Attributes/AngularJsonOnlyConfigurationAttribute.cs b/src/Umbraco.Web.Common/Filters/AngularJsonOnlyConfigurationAttribute.cs
similarity index 97%
rename from src/Umbraco.Web.Common/Attributes/AngularJsonOnlyConfigurationAttribute.cs
rename to src/Umbraco.Web.Common/Filters/AngularJsonOnlyConfigurationAttribute.cs
index f0281abcba..192b5e7df0 100644
--- a/src/Umbraco.Web.Common/Attributes/AngularJsonOnlyConfigurationAttribute.cs
+++ b/src/Umbraco.Web.Common/Filters/AngularJsonOnlyConfigurationAttribute.cs
@@ -9,7 +9,7 @@ using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Umbraco.Web.Common.Formatters;
-namespace Umbraco.Web.Common.Attributes
+namespace Umbraco.Web.Common.Filters
{
///
/// Applying this attribute to any controller will ensure that it only contains one json formatter compatible with the angular json vulnerability prevention.
@@ -38,4 +38,5 @@ namespace Umbraco.Web.Common.Attributes
base.OnResultExecuting(context);
}
}
+
}
diff --git a/src/Umbraco.Web.Common/Attributes/FeatureAuthorizeAttribute.cs b/src/Umbraco.Web.Common/Filters/FeatureAuthorizeAttribute.cs
similarity index 100%
rename from src/Umbraco.Web.Common/Attributes/FeatureAuthorizeAttribute.cs
rename to src/Umbraco.Web.Common/Filters/FeatureAuthorizeAttribute.cs
diff --git a/src/Umbraco.Web.Common/Filters/HttpResponseExceptionFilter.cs b/src/Umbraco.Web.Common/Filters/HttpResponseExceptionFilter.cs
index 46bfd6cdfa..cd2d2cb3a0 100644
--- a/src/Umbraco.Web.Common/Filters/HttpResponseExceptionFilter.cs
+++ b/src/Umbraco.Web.Common/Filters/HttpResponseExceptionFilter.cs
@@ -7,6 +7,11 @@ namespace Umbraco.Web.Common.Filters
{
public class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter
{
+ public HttpResponseExceptionFilter()
+ {
+
+ }
+
public int Order { get; set; } = int.MaxValue - 10;
public void OnActionExecuting(ActionExecutingContext context) { }
diff --git a/src/Umbraco.Web.Common/Install/InstallApiController.cs b/src/Umbraco.Web.Common/Install/InstallApiController.cs
index d9771fd7f8..c0c714a838 100644
--- a/src/Umbraco.Web.Common/Install/InstallApiController.cs
+++ b/src/Umbraco.Web.Common/Install/InstallApiController.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
using Newtonsoft.Json.Linq;
using Umbraco.Core;
using Umbraco.Core.Logging;
@@ -11,15 +12,20 @@ using Umbraco.Core.Migrations.Install;
using Umbraco.Net;
using Umbraco.Web.Common.Attributes;
using Umbraco.Web.Common.Exceptions;
+using Umbraco.Web.Common.Filters;
+using Umbraco.Web.Common.ModelBinding;
using Umbraco.Web.Install;
using Umbraco.Web.Install.Models;
namespace Umbraco.Web.Common.Install
{
+
+ [UmbracoApiController]
+ [TypeFilter(typeof(HttpResponseExceptionFilter))]
[TypeFilter(typeof(AngularJsonOnlyConfigurationAttribute))]
[HttpInstallAuthorize]
[Area("Install")]
- public class InstallApiController : Controller
+ public class InstallApiController : ControllerBase
{
private readonly DatabaseBuilder _databaseBuilder;
private readonly InstallStatusTracker _installStatusTracker;
@@ -28,10 +34,12 @@ namespace Umbraco.Web.Common.Install
private readonly ILogger _logger;
private readonly IProfilingLogger _proflog;
- public InstallApiController(DatabaseBuilder databaseBuilder, IProfilingLogger proflog,
+ public InstallApiController(UmbracoJsonModelBinderFactory modelBinderFactory, DatabaseBuilder databaseBuilder, IProfilingLogger proflog,
InstallHelper installHelper, InstallStepCollection installSteps, InstallStatusTracker installStatusTracker,
IUmbracoApplicationLifetime umbracoApplicationLifetime)
{
+ ModelBinderFactory = modelBinderFactory;
+
_databaseBuilder = databaseBuilder ?? throw new ArgumentNullException(nameof(databaseBuilder));
_proflog = proflog ?? throw new ArgumentNullException(nameof(proflog));
_installSteps = installSteps;
@@ -41,6 +49,7 @@ namespace Umbraco.Web.Common.Install
_logger = _proflog;
}
+
internal InstallHelper InstallHelper { get; }
public bool PostValidateDatabaseConnection(DatabaseModel model)
@@ -88,9 +97,8 @@ namespace Umbraco.Web.Common.Install
///
/// Installs.
- ///
- [HttpPost]
- public async Task PostPerformInstall([FromBody] InstallInstructions installModel)
+ ///
+ public async Task PostPerformInstall(InstallInstructions installModel)
{
if (installModel == null) throw new ArgumentNullException(nameof(installModel));
diff --git a/src/Umbraco.Web.Common/Install/InstallController.cs b/src/Umbraco.Web.Common/Install/InstallController.cs
index 88171820ec..07f0376697 100644
--- a/src/Umbraco.Web.Common/Install/InstallController.cs
+++ b/src/Umbraco.Web.Common/Install/InstallController.cs
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
+using System.Threading.Tasks;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Hosting;
@@ -11,6 +12,7 @@ using Umbraco.Web.Security;
namespace Umbraco.Web.Common.Install
{
+
///
/// The MVC Installation controller
///
@@ -49,7 +51,7 @@ namespace Umbraco.Web.Common.Install
[HttpGet]
[StatusCodeResult(System.Net.HttpStatusCode.ServiceUnavailable)]
[TypeFilter(typeof(StatusCodeResultAttribute), Arguments = new object []{System.Net.HttpStatusCode.ServiceUnavailable})]
- public ActionResult Index()
+ public async Task Index()
{
if (_runtime.Level == RuntimeLevel.Run)
return Redirect(_globalSettings.UmbracoPath.EnsureEndsWith('/'));
@@ -77,7 +79,7 @@ namespace Umbraco.Web.Common.Install
ViewData.SetUmbracoVersion(_umbracoVersion.SemanticVersion);
- _installHelper.InstallStatus(false, "");
+ await _installHelper.InstallStatus(false, "");
// always ensure full path (see NOTE in the class remarks)
return View();
diff --git a/src/Umbraco.Web.Common/Middleware/UmbracoRequestLoggingMiddleware.cs b/src/Umbraco.Web.Common/Middleware/UmbracoRequestLoggingMiddleware.cs
index 0e2158c939..b1d2d01f9d 100644
--- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestLoggingMiddleware.cs
+++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestLoggingMiddleware.cs
@@ -1,9 +1,10 @@
-using System.Threading.Tasks;
+using System;
+using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Extensions;
using Serilog.Context;
-using Umbraco.Core.Cache;
+using Umbraco.Core;
using Umbraco.Core.Logging.Serilog.Enrichers;
-using Umbraco.Net;
namespace Umbraco.Web.Common.Middleware
{
@@ -27,6 +28,13 @@ namespace Umbraco.Web.Common.Middleware
public async Task Invoke(HttpContext httpContext)
{
+ // do not process if client-side request
+ if (new Uri(httpContext.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsClientSideRequest())
+ {
+ await _next(httpContext);
+ return;
+ }
+
// TODO: Need to decide if we want this stuff still, there's new request logging in serilog:
// https://github.com/serilog/serilog-aspnetcore#request-logging which i think would suffice and replace all of this?
diff --git a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs
index e8695f3c9c..85cf6607cc 100644
--- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs
+++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs
@@ -1,25 +1,66 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Extensions;
using Umbraco.Web.Common.Lifetime;
+using Umbraco.Core;
+using Umbraco.Core.Logging;
namespace Umbraco.Web.Common.Middleware
{
+ ///
+ /// Manages Umbraco request objects and their lifetime
+ ///
public class UmbracoRequestMiddleware
{
private readonly RequestDelegate _next;
+ private readonly ILogger _logger;
private readonly IUmbracoRequestLifetimeManager _umbracoRequestLifetimeManager;
- public UmbracoRequestMiddleware(RequestDelegate next, IUmbracoRequestLifetimeManager umbracoRequestLifetimeManager)
+ private readonly IUmbracoContextFactory _umbracoContextFactory;
+
+ public UmbracoRequestMiddleware(RequestDelegate next,
+ ILogger logger,
+ IUmbracoRequestLifetimeManager umbracoRequestLifetimeManager,
+ IUmbracoContextFactory umbracoContextFactory)
{
_next = next;
+ _logger = logger;
_umbracoRequestLifetimeManager = umbracoRequestLifetimeManager;
+ _umbracoContextFactory = umbracoContextFactory;
}
public async Task InvokeAsync(HttpContext context)
{
- _umbracoRequestLifetimeManager.InitRequest(context);
- await _next(context);
- _umbracoRequestLifetimeManager.EndRequest(context);
+ // do not process if client-side request
+
+ if (new Uri(context.Request.GetEncodedUrl(), UriKind.RelativeOrAbsolute).IsClientSideRequest())
+ {
+ await _next(context);
+ return;
+ }
+
+ var umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext();
+
+ try
+ {
+ try
+ {
+ _umbracoRequestLifetimeManager.InitRequest(context);
+ }
+ catch (Exception ex)
+ {
+ // try catch so we don't kill everything in all requests
+ _logger.Error(ex);
+ }
+
+ await _next(context);
+
+ _umbracoRequestLifetimeManager.EndRequest(context);
+ }
+ finally
+ {
+ umbracoContextReference.Dispose();
+ }
}
}
}
diff --git a/src/Umbraco.Web.Common/ModelBinding/UmbracoJsonModelBinderProvider.cs b/src/Umbraco.Web.Common/ModelBinding/UmbracoJsonModelBinderProvider.cs
new file mode 100644
index 0000000000..120a6cf4f5
--- /dev/null
+++ b/src/Umbraco.Web.Common/ModelBinding/UmbracoJsonModelBinderProvider.cs
@@ -0,0 +1,117 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Formatters;
+using Microsoft.AspNetCore.Mvc.Infrastructure;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.ObjectPool;
+using Microsoft.Extensions.Options;
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Umbraco.Core;
+using Umbraco.Web.Common.Controllers;
+
+namespace Umbraco.Web.Common.ModelBinding
+{
+
+ public class UmbracoJsonModelBinderFactory : ModelBinderFactory
+ {
+ public UmbracoJsonModelBinderFactory(
+ UmbracoJsonModelBinderProvider umbracoJsonModelBinderProvider,
+ IModelMetadataProvider metadataProvider,
+ IOptions options,
+ IServiceProvider serviceProvider)
+ : base(metadataProvider, GetOptions(options, umbracoJsonModelBinderProvider), serviceProvider)
+ {
+ }
+
+ private static IOptions GetOptions(IOptions options, UmbracoJsonModelBinderProvider umbracoJsonModelBinderProvider)
+ {
+ // copy to new collection
+ var providers = options.Value.ModelBinderProviders.ToList();
+ // remove the default
+ providers.RemoveType();
+ // prepend our own
+ providers.Insert(0, umbracoJsonModelBinderProvider);
+ var newOptions = new MvcOptions();
+ foreach (var p in providers)
+ newOptions.ModelBinderProviders.Add(p);
+ return new CustomOptions(newOptions);
+ }
+
+ private class CustomOptions : IOptions
+ {
+ public CustomOptions(MvcOptions options)
+ {
+ Value = options;
+ }
+ public MvcOptions Value { get; }
+ }
+ }
+
+ public class UmbracoJsonModelBinder : BodyModelBinder, IModelBinder
+ {
+ public UmbracoJsonModelBinder(ArrayPool arrayPool, ObjectPoolProvider objectPoolProvider, IHttpRequestStreamReaderFactory readerFactory, ILoggerFactory loggerFactory)
+ : base(GetNewtonsoftJsonFormatter(loggerFactory, arrayPool, objectPoolProvider), readerFactory, loggerFactory)
+ {
+ }
+
+ internal static IInputFormatter[] GetNewtonsoftJsonFormatter(ILoggerFactory logger, ArrayPool arrayPool, ObjectPoolProvider objectPoolProvider)
+ {
+ var jsonOptions = new MvcNewtonsoftJsonOptions
+ {
+ AllowInputFormatterExceptionMessages = true
+ };
+ return new IInputFormatter[]
+ {
+ new NewtonsoftJsonInputFormatter(
+ logger.CreateLogger(),
+ jsonOptions.SerializerSettings, // Just use the defaults
+ arrayPool,
+ objectPoolProvider,
+ new MvcOptions(), // The only option that NewtonsoftJsonInputFormatter uses is SuppressInputFormatterBuffering
+ jsonOptions)
+ };
+ }
+
+ Task IModelBinder.BindModelAsync(ModelBindingContext bindingContext)
+ {
+ return BindModelAsync(bindingContext);
+ }
+ }
+
+ ///
+ /// A model binder for Umbraco models that require Newtonsoft Json serializers
+ ///
+ public class UmbracoJsonModelBinderProvider : BodyModelBinderProvider, IModelBinderProvider
+ {
+ public UmbracoJsonModelBinderProvider(IHttpRequestStreamReaderFactory readerFactory, ILoggerFactory logger, ArrayPool arrayPool, ObjectPoolProvider objectPoolProvider)
+ : base(UmbracoJsonModelBinder.GetNewtonsoftJsonFormatter(logger, arrayPool, objectPoolProvider), readerFactory)
+ {
+ }
+
+ ///
+ /// Returns the model binder if it's for Umbraco models
+ ///
+ ///
+ ///
+ IModelBinder IModelBinderProvider.GetBinder(ModelBinderProviderContext context)
+ {
+ // Must be 'Body' (json) binding
+ if (context.BindingInfo.BindingSource != BindingSource.Body)
+ return null;
+
+ if (context.Metadata?.UnderlyingOrModelType.Assembly == typeof(UmbracoJsonModelBinderProvider).Assembly // Umbraco.Web.Common
+ || context.Metadata?.UnderlyingOrModelType.Assembly == typeof(IRuntimeState).Assembly // Umbraco.Core
+ || context.Metadata?.UnderlyingOrModelType.Assembly == typeof(RuntimeState).Assembly) // Umbraco.Infrastructure
+ {
+ return GetBinder(context);
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/Umbraco.Web.Common/Runtime/Profiler/WebProfiler.cs b/src/Umbraco.Web.Common/Profiler/WebProfiler.cs
similarity index 94%
rename from src/Umbraco.Web.Common/Runtime/Profiler/WebProfiler.cs
rename to src/Umbraco.Web.Common/Profiler/WebProfiler.cs
index 958e134bab..30777d07a5 100644
--- a/src/Umbraco.Web.Common/Runtime/Profiler/WebProfiler.cs
+++ b/src/Umbraco.Web.Common/Profiler/WebProfiler.cs
@@ -7,8 +7,7 @@ using StackExchange.Profiling;
using Umbraco.Core;
using Umbraco.Core.Logging;
-// TODO: This namespace is strange, not sure why i has "Runtime" in the name?
-namespace Umbraco.Web.Common.Runtime.Profiler
+namespace Umbraco.Web.Common.Profiler
{
public class WebProfiler : IProfiler
@@ -45,9 +44,7 @@ namespace Umbraco.Web.Common.Runtime.Profiler
public void UmbracoApplicationBeginRequest(HttpContext context)
{
if (ShouldProfile(context.Request))
- {
Start();
- }
}
public void UmbracoApplicationEndRequest(HttpContext context)
diff --git a/src/Umbraco.Web.Common/Runtime/Profiler/WebProfilerComponent.cs b/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs
similarity index 98%
rename from src/Umbraco.Web.Common/Runtime/Profiler/WebProfilerComponent.cs
rename to src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs
index a36753e634..bc5cce9df1 100644
--- a/src/Umbraco.Web.Common/Runtime/Profiler/WebProfilerComponent.cs
+++ b/src/Umbraco.Web.Common/Profiler/WebProfilerComponent.cs
@@ -5,7 +5,7 @@ using Umbraco.Net;
using Umbraco.Web.Common.Lifetime;
using Umbraco.Web.Common.Middleware;
-namespace Umbraco.Web.Common.Runtime.Profiler
+namespace Umbraco.Web.Common.Profiler
{
internal sealed class WebProfilerComponent : IComponent
{
diff --git a/src/Umbraco.Web.Common/Runtime/Profiler/WebProfilerComposer.cs b/src/Umbraco.Web.Common/Profiler/WebProfilerComposer.cs
similarity index 88%
rename from src/Umbraco.Web.Common/Runtime/Profiler/WebProfilerComposer.cs
rename to src/Umbraco.Web.Common/Profiler/WebProfilerComposer.cs
index 523faf2da5..edb3db6f85 100644
--- a/src/Umbraco.Web.Common/Runtime/Profiler/WebProfilerComposer.cs
+++ b/src/Umbraco.Web.Common/Profiler/WebProfilerComposer.cs
@@ -1,7 +1,7 @@
using Umbraco.Core;
using Umbraco.Core.Composing;
-namespace Umbraco.Web.Common.Runtime.Profiler
+namespace Umbraco.Web.Common.Profiler
{
internal class WebProfilerComposer : ComponentComposer, ICoreComposer
{
diff --git a/src/Umbraco.Web.Common/Runtime/Profiler/WebProfilerHtml.cs b/src/Umbraco.Web.Common/Profiler/WebProfilerHtml.cs
similarity index 93%
rename from src/Umbraco.Web.Common/Runtime/Profiler/WebProfilerHtml.cs
rename to src/Umbraco.Web.Common/Profiler/WebProfilerHtml.cs
index 9e989d6b5c..40c245dd5a 100644
--- a/src/Umbraco.Web.Common/Runtime/Profiler/WebProfilerHtml.cs
+++ b/src/Umbraco.Web.Common/Profiler/WebProfilerHtml.cs
@@ -5,8 +5,7 @@ using StackExchange.Profiling;
using StackExchange.Profiling.Internal;
using Umbraco.Core.Logging;
-// TODO: This namespace is strange, not sure why i has "Runtime" in the name?
-namespace Umbraco.Web.Common.Runtime.Profiler
+namespace Umbraco.Web.Common.Profiler
{
public class WebProfilerHtml : IProfilerHtml
{
diff --git a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs
index 30d7cdaced..78068b551c 100644
--- a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs
+++ b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs
@@ -12,8 +12,8 @@ using Umbraco.Web.Common.Macros;
using Umbraco.Web.Composing.CompositionExtensions;
using Umbraco.Web.Macros;
using Umbraco.Core.Diagnostics;
-using Umbraco.Web.Common.Runtime.Profiler;
using Umbraco.Core.Logging;
+using Umbraco.Web.Common.Profiler;
namespace Umbraco.Web.Common.Runtime
{
diff --git a/src/Umbraco.Web.Common/Security/WebSecurity.cs b/src/Umbraco.Web.Common/Security/WebSecurity.cs
new file mode 100644
index 0000000000..5f54d2e9ee
--- /dev/null
+++ b/src/Umbraco.Web.Common/Security/WebSecurity.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Umbraco.Core;
+using Umbraco.Core.Models.Membership;
+using Umbraco.Web.Security;
+
+namespace Umbraco.Web.Common.Security
+{
+ // TODO: need to implement this
+
+ public class WebSecurity : IWebSecurity
+ {
+ public IUser CurrentUser => throw new NotImplementedException();
+
+ public ValidateRequestAttempt AuthorizeRequest(bool throwExceptions = false)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void ClearCurrentLogin()
+ {
+ throw new NotImplementedException();
+ }
+
+ public Attempt GetUserId()
+ {
+ throw new NotImplementedException();
+ }
+
+ public bool IsAuthenticated()
+ {
+ throw new NotImplementedException();
+ }
+
+ public double PerformLogin(int userId)
+ {
+ throw new NotImplementedException();
+ }
+
+ public bool UserHasSectionAccess(string section, IUser user)
+ {
+ throw new NotImplementedException();
+ }
+
+ public bool ValidateCurrentUser()
+ {
+ throw new NotImplementedException();
+ }
+
+ public ValidateRequestAttempt ValidateCurrentUser(bool throwExceptions, bool requiresApproval = true)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj
index eed88bc491..9f6509cd82 100644
--- a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj
+++ b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj
@@ -21,6 +21,7 @@
+
diff --git a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContextFactory.cs b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContextFactory.cs
index 97f009968c..89751bfa08 100644
--- a/src/Umbraco.Web.Common/UmbracoContext/UmbracoContextFactory.cs
+++ b/src/Umbraco.Web.Common/UmbracoContext/UmbracoContextFactory.cs
@@ -6,6 +6,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Hosting;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
+using Umbraco.Web.Common.Security;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Security;
@@ -16,8 +17,6 @@ namespace Umbraco.Web
///
public class UmbracoContextFactory : IUmbracoContextFactory
{
- private static readonly NullWriter NullWriterInstance = new NullWriter();
-
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IPublishedSnapshotService _publishedSnapshotService;
private readonly IVariationContextAccessor _variationContextAccessor;
@@ -73,7 +72,7 @@ namespace Umbraco.Web
_variationContextAccessor.VariationContext = new VariationContext(_defaultCultureAccessor.DefaultCulture);
}
- IWebSecurity webSecurity = null; // TODO, we need to when users are migrated
+ IWebSecurity webSecurity = new WebSecurity();
return new UmbracoContext(
_publishedSnapshotService,
diff --git a/src/Umbraco.Web.UI.Client/src/installer/installer.service.js b/src/Umbraco.Web.UI.Client/src/installer/installer.service.js
index 7cebaaada3..1003b19b20 100644
--- a/src/Umbraco.Web.UI.Client/src/installer/installer.service.js
+++ b/src/Umbraco.Web.UI.Client/src/installer/installer.service.js
@@ -336,7 +336,10 @@ angular.module("umbraco.install").factory('installerService', function ($rootSco
if (status >= 500 && status < 600) {
service.status.current = { view: "ysod", model: null };
var ysod = data;
- //we need to manually write the html to the iframe - the html contains full html markup
+ //we need to manually write the html to the iframe
+ // TODO: In dotnetcore the resulting YSOD isn't HTML, the error is just a string so it looks ugly
+ // So we shouldn't be using an iframe and will need to change this so that we have an unhandled exception filter for the installer (and eventually
+ // the rest of the back office) to handle errors and chuck the data into a json format for us to use.
$timeout(function () {
document.getElementById('ysod').contentDocument.write(ysod);
}, 500);
diff --git a/src/Umbraco.Web.UI.NetCore/Startup.cs b/src/Umbraco.Web.UI.NetCore/Startup.cs
index f74208bac6..bd23ef4229 100644
--- a/src/Umbraco.Web.UI.NetCore/Startup.cs
+++ b/src/Umbraco.Web.UI.NetCore/Startup.cs
@@ -53,20 +53,10 @@ namespace Umbraco.Web.UI.BackOffice
{
services.AddUmbracoConfiguration(_config);
services.AddUmbracoCore(_env, out var factory);
- services.AddUmbracoWebsite();
+ services.AddUmbracoWebComponents();
services.AddUmbracoRuntimeMinifier(_config);
- services.AddMvc(options =>
- {
- options.Filters.Add();
-
- }).SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
- .AddNewtonsoftJson(options =>
- {
- options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
-
- })
- ;
+ services.AddMvc();
services.AddMiniProfiler(options =>
{
@@ -90,19 +80,24 @@ namespace Umbraco.Web.UI.BackOffice
public void Configure(IApplicationBuilder app)
{
- //app.UseMiniProfiler();
- app.UseUmbracoRequestLifetime();
+ //app.UseMiniProfiler();
if (_env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
+
app.UseStatusCodePages();
+ app.UseRouting();
+
+
+ app.UseUmbracoRouting();
app.UseUmbracoCore();
app.UseUmbracoRequestLogging();
app.UseUmbracoWebsite();
- app.UseUmbracoBackOffice();
- app.UseRouting();
+ app.UseUmbracoBackOffice();
app.UseUmbracoRuntimeMinification();
+
+
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute("Backoffice", "/umbraco/{Action}", new
@@ -111,7 +106,7 @@ namespace Umbraco.Web.UI.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
diff --git a/src/Umbraco.Web.Website/AspNetCore/UmbracoWebsiteServiceCollectionExtensions.cs b/src/Umbraco.Web.Website/AspNetCore/UmbracoWebsiteServiceCollectionExtensions.cs
deleted file mode 100644
index 3a327ef867..0000000000
--- a/src/Umbraco.Web.Website/AspNetCore/UmbracoWebsiteServiceCollectionExtensions.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-using System.Collections.Generic;
-using Microsoft.Extensions.DependencyInjection;
-using SixLabors.ImageSharp.Memory;
-using SixLabors.ImageSharp.Web.Caching;
-using SixLabors.ImageSharp.Web.Commands;
-using SixLabors.ImageSharp.Web.DependencyInjection;
-using SixLabors.ImageSharp.Web.Processors;
-using SixLabors.ImageSharp.Web.Providers;
-
-using Umbraco.Core;
-using Umbraco.Core.Configuration;
-
-namespace Umbraco.Web.Website.AspNetCore
-{
- public static class UmbracoBackOfficeServiceCollectionExtensions
- {
- public static IServiceCollection AddUmbracoWebsite(this IServiceCollection services)
- {
- // TODO: We need to avoid this, surely there's a way? See ContainerTests.BuildServiceProvider_Before_Host_Is_Configured
- var serviceProvider = services.BuildServiceProvider();
- var configs = serviceProvider.GetService();
- var imagingSettings = configs.Imaging();
- services.AddUmbracoImageSharp(imagingSettings);
-
- return services;
- }
-
- public static IServiceCollection AddUmbracoImageSharp(this IServiceCollection services, IImagingSettings imagingSettings)
- {
-
-
- services.AddImageSharpCore(
- options =>
- {
- options.Configuration = SixLabors.ImageSharp.Configuration.Default;
- options.MaxBrowserCacheDays = imagingSettings.MaxBrowserCacheDays;
- options.MaxCacheDays = imagingSettings.MaxCacheDays;
- options.CachedNameLength = imagingSettings.CachedNameLength;
- options.OnParseCommands = context =>
- {
- RemoveIntParamenterIfValueGreatherThen(context.Commands, ResizeWebProcessor.Width, imagingSettings.MaxResizeWidth);
- RemoveIntParamenterIfValueGreatherThen(context.Commands, ResizeWebProcessor.Height, imagingSettings.MaxResizeHeight);
- };
- options.OnBeforeSave = _ => { };
- options.OnProcessed = _ => { };
- options.OnPrepareResponse = _ => { };
- })
- .SetRequestParser()
- .SetMemoryAllocator(provider => ArrayPoolMemoryAllocator.CreateWithMinimalPooling())
- .Configure(options =>
- {
- options.CacheFolder = imagingSettings.CacheFolder;
- })
- .SetCache()
- .SetCacheHash()
- .AddProvider()
- .AddProcessor()
- .AddProcessor()
- .AddProcessor();
-
- return services;
- }
-
- private static void RemoveIntParamenterIfValueGreatherThen(IDictionary commands, string parameter, int maxValue)
- {
- if (commands.TryGetValue(parameter, out var command))
- {
- if (int.TryParse(command, out var i))
- {
- if (i > maxValue)
- {
- commands.Remove(parameter);
- }
- }
- }
- }
- }
-
-}