// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Buffers; using System.Linq; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewComponents; using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; namespace Microsoft.Extensions.DependencyInjection { public static class MvcViewFeaturesMvcCoreBuilderExtensions { public static IMvcCoreBuilder AddViews(this IMvcCoreBuilder builder) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } builder.AddDataAnnotations(); AddViewComponentApplicationPartsProviders(builder.PartManager); AddViewServices(builder.Services); return builder; } /// /// Registers as the default in the /// . Also registers the default view services. /// /// The . /// The . public static IMvcCoreBuilder AddCookieTempDataProvider(this IMvcCoreBuilder builder) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } // Ensure the TempData basics are registered. AddViewServices(builder.Services); var descriptor = ServiceDescriptor.Singleton(typeof(ITempDataProvider), typeof(CookieTempDataProvider)); builder.Services.Replace(descriptor); return builder; } private static void AddViewComponentApplicationPartsProviders(ApplicationPartManager manager) { if (!manager.FeatureProviders.OfType().Any()) { manager.FeatureProviders.Add(new ViewComponentFeatureProvider()); } } public static IMvcCoreBuilder AddViews( this IMvcCoreBuilder builder, Action setupAction) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (setupAction == null) { throw new ArgumentNullException(nameof(setupAction)); } AddViews(builder); builder.Services.Configure(setupAction); return builder; } /// /// Registers as the default in the /// . Also registers the default view services. /// /// The . /// /// An to configure the provided /// . /// /// The . public static IMvcCoreBuilder AddCookieTempDataProvider( this IMvcCoreBuilder builder, Action setupAction) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (setupAction == null) { throw new ArgumentNullException(nameof(setupAction)); } AddCookieTempDataProvider(builder); builder.Services.Configure(setupAction); return builder; } public static IMvcCoreBuilder ConfigureViews( this IMvcCoreBuilder builder, Action setupAction) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (setupAction == null) { throw new ArgumentNullException(nameof(setupAction)); } builder.Services.Configure(setupAction); return builder; } // Internal for testing. internal static void AddViewServices(IServiceCollection services) { services.AddDataProtection(); services.AddAntiforgery(); services.AddWebEncoders(); services.TryAddEnumerable( ServiceDescriptor.Transient, MvcViewOptionsSetup>()); services.TryAddEnumerable( ServiceDescriptor.Transient, MvcViewOptionsConfigureCompatibilityOptions>()); services.TryAddEnumerable( ServiceDescriptor.Transient, TempDataMvcOptionsSetup>()); // // View Engine and related infrastructure // services.TryAddSingleton(); services.TryAddSingleton, ViewResultExecutor>(); services.TryAddSingleton, PartialViewResultExecutor>(); // Support for activating ViewDataDictionary services.TryAddEnumerable( ServiceDescriptor .Transient()); // // HTML Helper // services.TryAddTransient(); services.TryAddTransient(typeof(IHtmlHelper<>), typeof(HtmlHelper<>)); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); // // JSON Helper // services.TryAddSingleton(); services.TryAdd(ServiceDescriptor.Singleton(serviceProvider => { var options = serviceProvider.GetRequiredService>().Value; var charPool = serviceProvider.GetRequiredService>(); return new JsonOutputFormatter(options.SerializerSettings, charPool); })); // // View Components // // These do caching so they should stay singleton services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton< IViewComponentDescriptorCollectionProvider, DefaultViewComponentDescriptorCollectionProvider>(); services.TryAddSingleton, ViewComponentResultExecutor>(); services.TryAddSingleton(); services.TryAddTransient(); services.TryAddSingleton(); services.TryAddTransient(); // // Temp Data // services.TryAddEnumerable( ServiceDescriptor.Transient()); services.TryAddEnumerable( ServiceDescriptor.Transient()); services.TryAddSingleton(); services.TryAddTransient(); // This does caching so it should stay singleton services.TryAddSingleton(); // // Antiforgery // services.TryAddSingleton(); services.TryAddSingleton(); // These are stateless so their lifetime isn't really important. services.TryAddSingleton(); services.TryAddSingleton(ArrayPool.Shared); services.TryAddScoped(); } } }