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.Middleware; 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.ConfigureOptions(); services.TryAddEnumerable(ServiceDescriptor.Transient()); 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 globally configuring MVC for Umbraco /// /// /// 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 { // TODO: we can inject params with DI here public UmbracoMvcConfigureOptions() { } // TODO: we can configure global mvc options here if we need to public void Configure(MvcOptions options) { } } } }