diff --git a/src/Mvc/Mvc.Core/src/Builder/ControllerEndpointRouteBuilderExtensions.cs b/src/Mvc/Mvc.Core/src/Builder/ControllerEndpointRouteBuilderExtensions.cs index 03d25e70c2..726988fd6f 100644 --- a/src/Mvc/Mvc.Core/src/Builder/ControllerEndpointRouteBuilderExtensions.cs +++ b/src/Mvc/Mvc.Core/src/Builder/ControllerEndpointRouteBuilderExtensions.cs @@ -450,7 +450,7 @@ namespace Microsoft.AspNetCore.Builder { throw new InvalidOperationException(Resources.FormatUnableToFindServices( nameof(IServiceCollection), - "AddMvc", + "AddControllers", "ConfigureServices(...)")); } } diff --git a/src/Mvc/Mvc.Razor/src/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs b/src/Mvc/Mvc.Razor/src/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs index fdd018eca7..fc94c6d209 100644 --- a/src/Mvc/Mvc.Razor/src/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs +++ b/src/Mvc/Mvc.Razor/src/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs @@ -28,7 +28,7 @@ namespace Microsoft.Extensions.DependencyInjection } builder.AddViews(); - AddRazorViewEngineFeatureProviders(builder); + AddRazorViewEngineFeatureProviders(builder.PartManager); AddRazorViewEngineServices(builder.Services); return builder; } @@ -49,7 +49,7 @@ namespace Microsoft.Extensions.DependencyInjection builder.AddViews(); - AddRazorViewEngineFeatureProviders(builder); + AddRazorViewEngineFeatureProviders(builder.PartManager); AddRazorViewEngineServices(builder.Services); builder.Services.Configure(setupAction); @@ -57,20 +57,20 @@ namespace Microsoft.Extensions.DependencyInjection return builder; } - private static void AddRazorViewEngineFeatureProviders(IMvcCoreBuilder builder) + internal static void AddRazorViewEngineFeatureProviders(ApplicationPartManager partManager) { - if (!builder.PartManager.FeatureProviders.OfType().Any()) + if (!partManager.FeatureProviders.OfType().Any()) { - builder.PartManager.FeatureProviders.Add(new TagHelperFeatureProvider()); + partManager.FeatureProviders.Add(new TagHelperFeatureProvider()); } // ViewFeature items have precedence semantics - when two views have the same path \ identifier, // the one that appears earlier in the list wins. Therefore the ordering of // RazorCompiledItemFeatureProvider and ViewsFeatureProvider is pertinent - any view compiled // using the Sdk will be preferred to views compiled using MvcPrecompilation. - if (!builder.PartManager.FeatureProviders.OfType().Any()) + if (!partManager.FeatureProviders.OfType().Any()) { - builder.PartManager.FeatureProviders.Add(new RazorCompiledItemFeatureProvider()); + partManager.FeatureProviders.Add(new RazorCompiledItemFeatureProvider()); } } diff --git a/src/Mvc/Mvc.Razor/src/Properties/AssemblyInfo.cs b/src/Mvc/Mvc.Razor/src/Properties/AssemblyInfo.cs index db40b79a34..3d28953a21 100644 --- a/src/Mvc/Mvc.Razor/src/Properties/AssemblyInfo.cs +++ b/src/Mvc/Mvc.Razor/src/Properties/AssemblyInfo.cs @@ -3,6 +3,7 @@ using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.RazorPages, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.TagHelpers, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Mvc/Mvc.RazorPages/src/Builder/RazorPagesEndpointRouteBuilderExtensions.cs b/src/Mvc/Mvc.RazorPages/src/Builder/RazorPagesEndpointRouteBuilderExtensions.cs index 90a9dd0657..22b38e041c 100644 --- a/src/Mvc/Mvc.RazorPages/src/Builder/RazorPagesEndpointRouteBuilderExtensions.cs +++ b/src/Mvc/Mvc.RazorPages/src/Builder/RazorPagesEndpointRouteBuilderExtensions.cs @@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.Builder /// /// does not re-execute routing, and will /// not generate route values based on routes defined elsewhere. When using this overload, the path route value - /// will be available. + /// will be available. /// /// public static void MapFallbackToPage(this IEndpointRouteBuilder endpoints, string page) @@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.Builder GetOrCreateDataSource(endpoints); // Maps a fallback endpoint with an empty delegate. This is OK because - // we don't expect the delegate to run. + // we don't expect the delegate to run. endpoints.MapFallback(context => Task.CompletedTask).Add(b => { // MVC registers a policy that looks for this metadata. @@ -109,8 +109,8 @@ namespace Microsoft.AspNetCore.Builder /// /// /// does not re-execute routing, and will - /// not generate route values based on routes defined elsewhere. When using this overload, the route values provided by matching - /// will be available. + /// not generate route values based on routes defined elsewhere. When using this overload, the route values provided by matching + /// will be available. /// /// public static void MapFallbackToPage( @@ -141,7 +141,7 @@ namespace Microsoft.AspNetCore.Builder GetOrCreateDataSource(endpoints); // Maps a fallback endpoint with an empty delegate. This is OK because - // we don't expect the delegate to run. + // we don't expect the delegate to run. endpoints.MapFallback(pattern, context => Task.CompletedTask).Add(b => { // MVC registers a policy that looks for this metadata. @@ -171,7 +171,7 @@ namespace Microsoft.AspNetCore.Builder /// /// does not re-execute routing, and will /// not generate route values based on routes defined elsewhere. When using this overload, the path route value - /// will be available. + /// will be available. /// /// public static void MapFallbackToAreaPage( @@ -197,7 +197,7 @@ namespace Microsoft.AspNetCore.Builder GetOrCreateDataSource(endpoints); // Maps a fallback endpoint with an empty delegate. This is OK because - // we don't expect the delegate to run. + // we don't expect the delegate to run. endpoints.MapFallback(context => Task.CompletedTask).Add(b => { // MVC registers a policy that looks for this metadata. @@ -230,7 +230,7 @@ namespace Microsoft.AspNetCore.Builder /// /// /// does not re-execute routing, and will - /// not generate route values based on routes defined elsewhere. When using this overload, the route values provided by matching + /// not generate route values based on routes defined elsewhere. When using this overload, the route values provided by matching /// will be available. /// /// @@ -263,7 +263,7 @@ namespace Microsoft.AspNetCore.Builder GetOrCreateDataSource(endpoints); // Maps a fallback endpoint with an empty delegate. This is OK because - // we don't expect the delegate to run. + // we don't expect the delegate to run. endpoints.MapFallback(pattern, context => Task.CompletedTask).Add(b => { // MVC registers a policy that looks for this metadata. @@ -287,7 +287,7 @@ namespace Microsoft.AspNetCore.Builder { throw new InvalidOperationException(Mvc.Core.Resources.FormatUnableToFindServices( nameof(IServiceCollection), - "AddMvc", + "AddRazorPages", "ConfigureServices(...)")); } } diff --git a/src/Mvc/Mvc.RazorPages/src/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs b/src/Mvc/Mvc.RazorPages/src/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs index bc62660748..6a4f62dff3 100644 --- a/src/Mvc/Mvc.RazorPages/src/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs +++ b/src/Mvc/Mvc.RazorPages/src/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs @@ -26,7 +26,7 @@ namespace Microsoft.Extensions.DependencyInjection builder.AddRazorViewEngine(); - AddServices(builder.Services); + AddRazorPagesServices(builder.Services); return builder; } @@ -47,7 +47,7 @@ namespace Microsoft.Extensions.DependencyInjection builder.AddRazorViewEngine(); - AddServices(builder.Services); + AddRazorPagesServices(builder.Services); builder.Services.Configure(setupAction); @@ -77,7 +77,7 @@ namespace Microsoft.Extensions.DependencyInjection } // Internal for testing. - internal static void AddServices(IServiceCollection services) + internal static void AddRazorPagesServices(IServiceCollection services) { // Options services.TryAddEnumerable( diff --git a/src/Mvc/Mvc.RazorPages/src/Properties/AssemblyInfo.cs b/src/Mvc/Mvc.RazorPages/src/Properties/AssemblyInfo.cs index 5f7daf43f9..0d51e4a81b 100644 --- a/src/Mvc/Mvc.RazorPages/src/Properties/AssemblyInfo.cs +++ b/src/Mvc/Mvc.RazorPages/src/Properties/AssemblyInfo.cs @@ -3,6 +3,8 @@ using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] + [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.IntegrationTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.RazorPages.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Mvc/Mvc.TagHelpers/src/DependencyInjection/TagHelperExtensions.cs b/src/Mvc/Mvc.TagHelpers/src/DependencyInjection/TagHelperExtensions.cs index e39242536a..74b3ef5853 100644 --- a/src/Mvc/Mvc.TagHelpers/src/DependencyInjection/TagHelperExtensions.cs +++ b/src/Mvc/Mvc.TagHelpers/src/DependencyInjection/TagHelperExtensions.cs @@ -25,13 +25,7 @@ namespace Microsoft.Extensions.DependencyInjection throw new ArgumentNullException(nameof(builder)); } - builder.Services.TryAddSingleton(); - builder.Services.TryAddSingleton(); - builder.Services.TryAddSingleton(); - - // Required default services for cache tag helpers - builder.Services.AddDistributedMemoryCache(); - builder.Services.TryAddSingleton(); + AddCacheTagHelperServices(builder.Services); return builder; } @@ -81,5 +75,16 @@ namespace Microsoft.Extensions.DependencyInjection return builder; } + + internal static void AddCacheTagHelperServices(IServiceCollection services) + { + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + + // Required default services for cache tag helpers + services.AddDistributedMemoryCache(); + services.TryAddSingleton(); + } } } \ No newline at end of file diff --git a/src/Mvc/Mvc.TagHelpers/src/Properties/AssemblyInfo.cs b/src/Mvc/Mvc.TagHelpers/src/Properties/AssemblyInfo.cs index 4516d25702..bfd89af653 100644 --- a/src/Mvc/Mvc.TagHelpers/src/Properties/AssemblyInfo.cs +++ b/src/Mvc/Mvc.TagHelpers/src/Properties/AssemblyInfo.cs @@ -3,5 +3,6 @@ using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.TagHelpers.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] diff --git a/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs b/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs index 285ba5aec5..faeeebb79d 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs @@ -63,7 +63,7 @@ namespace Microsoft.Extensions.DependencyInjection return builder; } - private static void AddViewComponentApplicationPartsProviders(ApplicationPartManager manager) + internal static void AddViewComponentApplicationPartsProviders(ApplicationPartManager manager) { if (!manager.FeatureProviders.OfType().Any()) { diff --git a/src/Mvc/Mvc.ViewFeatures/src/PartialViewResult.cs b/src/Mvc/Mvc.ViewFeatures/src/PartialViewResult.cs index 56b0f80139..3213e16c28 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/PartialViewResult.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/PartialViewResult.cs @@ -65,7 +65,15 @@ namespace Microsoft.AspNetCore.Mvc } var services = context.HttpContext.RequestServices; - var executor = services.GetRequiredService>(); + var executor = services.GetService>(); + if (executor == null) + { + throw new InvalidOperationException(Mvc.Core.Resources.FormatUnableToFindServices( + nameof(IServiceCollection), + "AddControllersWithViews()", + "ConfigureServices(...)")); + } + return executor.ExecuteAsync(context, this); } } diff --git a/src/Mvc/Mvc.ViewFeatures/src/Properties/AssemblyInfo.cs b/src/Mvc/Mvc.ViewFeatures/src/Properties/AssemblyInfo.cs index 01241ba199..b677034d2d 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/Properties/AssemblyInfo.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/Properties/AssemblyInfo.cs @@ -3,6 +3,7 @@ using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.RazorPages, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.TagHelpers, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Mvc/Mvc.ViewFeatures/src/ViewComponentResult.cs b/src/Mvc/Mvc.ViewFeatures/src/ViewComponentResult.cs index 433f44eff4..f4d2385ea5 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/ViewComponentResult.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/ViewComponentResult.cs @@ -64,7 +64,15 @@ namespace Microsoft.AspNetCore.Mvc } var services = context.HttpContext.RequestServices; - var executor = services.GetRequiredService>(); + var executor = services.GetService>(); + if (executor == null) + { + throw new InvalidOperationException(Mvc.Core.Resources.FormatUnableToFindServices( + nameof(IServiceCollection), + "AddControllersWithViews()", + "ConfigureServices(...)")); + } + return executor.ExecuteAsync(context, this); } } diff --git a/src/Mvc/Mvc.ViewFeatures/src/ViewResult.cs b/src/Mvc/Mvc.ViewFeatures/src/ViewResult.cs index 5534ec8666..d99aaefa0d 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/ViewResult.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/ViewResult.cs @@ -64,7 +64,15 @@ namespace Microsoft.AspNetCore.Mvc throw new ArgumentNullException(nameof(context)); } - var executor = context.HttpContext.RequestServices.GetRequiredService>(); + var executor = context.HttpContext.RequestServices.GetService>(); + if (executor == null) + { + throw new InvalidOperationException(Mvc.Core.Resources.FormatUnableToFindServices( + nameof(IServiceCollection), + "AddControllersWithViews()", + "ConfigureServices(...)")); + } + await executor.ExecuteAsync(context, this); } } diff --git a/src/Mvc/Mvc.ViewFeatures/test/PartialViewResultTest.cs b/src/Mvc/Mvc.ViewFeatures/test/PartialViewResultTest.cs index a78e3a103c..c80077b088 100644 --- a/src/Mvc/Mvc.ViewFeatures/test/PartialViewResultTest.cs +++ b/src/Mvc/Mvc.ViewFeatures/test/PartialViewResultTest.cs @@ -42,6 +42,25 @@ namespace Microsoft.AspNetCore.Mvc Assert.Same(customModel, viewResult.Model); } + [Fact] + public async Task ExecuteResultAsync_Throws_IfServicesNotRegistered() + { + // Arrange + var actionContext = new ActionContext(new DefaultHttpContext() { RequestServices = Mock.Of(), }, new RouteData(), new ActionDescriptor()); + var expected = + $"Unable to find the required services. Please add all the required services by calling " + + $"'IServiceCollection.AddControllersWithViews()' inside the call to 'ConfigureServices(...)' " + + $"in the application startup code."; + + var viewResult = new PartialViewResult(); + + // Act + var ex = await Assert.ThrowsAsync(() => viewResult.ExecuteResultAsync(actionContext)); + + // Assert + Assert.Equal(expected, ex.Message); + } + [Fact] public async Task ExecuteResultAsync_Throws_IfViewCouldNotBeFound_MessageUsesGetViewLocations() { diff --git a/src/Mvc/Mvc.ViewFeatures/test/ViewComponentResultTest.cs b/src/Mvc/Mvc.ViewFeatures/test/ViewComponentResultTest.cs index ebc324dbea..2c65acccb2 100644 --- a/src/Mvc/Mvc.ViewFeatures/test/ViewComponentResultTest.cs +++ b/src/Mvc/Mvc.ViewFeatures/test/ViewComponentResultTest.cs @@ -52,6 +52,25 @@ namespace Microsoft.AspNetCore.Mvc Assert.Same(customModel, viewResult.Model); } + [Fact] + public async Task ExecuteResultAsync_Throws_IfServicesNotRegistered() + { + // Arrange + var actionContext = new ActionContext(new DefaultHttpContext() { RequestServices = Mock.Of(), }, new RouteData(), new ActionDescriptor()); + var expected = + $"Unable to find the required services. Please add all the required services by calling " + + $"'IServiceCollection.AddControllersWithViews()' inside the call to 'ConfigureServices(...)' " + + $"in the application startup code."; + + var viewResult = new ViewComponentResult(); + + // Act + var ex = await Assert.ThrowsAsync(() => viewResult.ExecuteResultAsync(actionContext)); + + // Assert + Assert.Equal(expected, ex.Message); + } + [Fact] public async Task ExecuteAsync_ViewComponentResult_AllowsNullViewDataAndTempData() { diff --git a/src/Mvc/Mvc.ViewFeatures/test/ViewResultTest.cs b/src/Mvc/Mvc.ViewFeatures/test/ViewResultTest.cs index c05b10c071..fbb203f8d5 100644 --- a/src/Mvc/Mvc.ViewFeatures/test/ViewResultTest.cs +++ b/src/Mvc/Mvc.ViewFeatures/test/ViewResultTest.cs @@ -52,6 +52,25 @@ namespace Microsoft.AspNetCore.Mvc Assert.Same(customModel, viewResult.Model); } + [Fact] + public async Task ExecuteResultAsync_Throws_IfServicesNotRegistered() + { + // Arrange + var actionContext = new ActionContext(new DefaultHttpContext() { RequestServices = Mock.Of(), }, new RouteData(), new ActionDescriptor()); + var expected = + $"Unable to find the required services. Please add all the required services by calling " + + $"'IServiceCollection.AddControllersWithViews()' inside the call to 'ConfigureServices(...)' " + + $"in the application startup code."; + + var viewResult = new ViewResult(); + + // Act + var ex = await Assert.ThrowsAsync(() => viewResult.ExecuteResultAsync(actionContext)); + + // Assert + Assert.Equal(expected, ex.Message); + } + [Fact] public async Task ExecuteResultAsync_Throws_IfViewCouldNotBeFound_MessageUsesGetViewLocations() { diff --git a/src/Mvc/Mvc/ref/Microsoft.AspNetCore.Mvc.netcoreapp3.0.cs b/src/Mvc/Mvc/ref/Microsoft.AspNetCore.Mvc.netcoreapp3.0.cs index bf170d8931..4ee7b115b5 100644 --- a/src/Mvc/Mvc/ref/Microsoft.AspNetCore.Mvc.netcoreapp3.0.cs +++ b/src/Mvc/Mvc/ref/Microsoft.AspNetCore.Mvc.netcoreapp3.0.cs @@ -5,7 +5,13 @@ namespace Microsoft.Extensions.DependencyInjection { public static partial class MvcServiceCollectionExtensions { + public static Microsoft.Extensions.DependencyInjection.IMvcBuilder AddControllers(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) { throw null; } + public static Microsoft.Extensions.DependencyInjection.IMvcBuilder AddControllers(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configure) { throw null; } + public static Microsoft.Extensions.DependencyInjection.IMvcBuilder AddControllersWithViews(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) { throw null; } + public static Microsoft.Extensions.DependencyInjection.IMvcBuilder AddControllersWithViews(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configure) { throw null; } public static Microsoft.Extensions.DependencyInjection.IMvcBuilder AddMvc(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) { throw null; } public static Microsoft.Extensions.DependencyInjection.IMvcBuilder AddMvc(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action setupAction) { throw null; } + public static Microsoft.Extensions.DependencyInjection.IMvcBuilder AddRazorPages(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) { throw null; } + public static Microsoft.Extensions.DependencyInjection.IMvcBuilder AddRazorPages(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configure) { throw null; } } } diff --git a/src/Mvc/Mvc/src/MvcServiceCollectionExtensions.cs b/src/Mvc/Mvc/src/MvcServiceCollectionExtensions.cs index eb045d1900..ffb69ee504 100644 --- a/src/Mvc/Mvc/src/MvcServiceCollectionExtensions.cs +++ b/src/Mvc/Mvc/src/MvcServiceCollectionExtensions.cs @@ -9,6 +9,7 @@ using System.Reflection; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.AspNetCore.Mvc.Razor.TagHelpers; +using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Mvc.TagHelpers; namespace Microsoft.Extensions.DependencyInjection @@ -30,43 +31,8 @@ namespace Microsoft.Extensions.DependencyInjection throw new ArgumentNullException(nameof(services)); } - var builder = services.AddMvcCore(); - - builder.AddApiExplorer(); - builder.AddAuthorization(); - - AddDefaultFrameworkParts(builder.PartManager); - - // Order added affects options setup order - - // Default framework order - builder.AddFormatterMappings(); - builder.AddViews(); - builder.AddRazorViewEngine(); - builder.AddRazorPages(); - builder.AddCacheTagHelper(); - - // +1 order - builder.AddDataAnnotations(); // +1 order - - builder.AddCors(); - - return new MvcBuilder(builder.Services, builder.PartManager); - } - - private static void AddDefaultFrameworkParts(ApplicationPartManager partManager) - { - var mvcTagHelpersAssembly = typeof(InputTagHelper).GetTypeInfo().Assembly; - if (!partManager.ApplicationParts.OfType().Any(p => p.Assembly == mvcTagHelpersAssembly)) - { - partManager.ApplicationParts.Add(new FrameworkAssemblyPart(mvcTagHelpersAssembly)); - } - - var mvcRazorAssembly = typeof(UrlResolutionTagHelper).GetTypeInfo().Assembly; - if (!partManager.ApplicationParts.OfType().Any(p => p.Assembly == mvcRazorAssembly)) - { - partManager.ApplicationParts.Add(new FrameworkAssemblyPart(mvcRazorAssembly)); - } + services.AddControllersWithViews(); + return services.AddRazorPages(); } /// @@ -93,6 +59,283 @@ namespace Microsoft.Extensions.DependencyInjection return builder; } + /// + /// Adds services for controllers to the specified . This method will not + /// register services used for views or pages. + /// + /// The to add services to. + /// An that can be used to further configure the MVC services. + /// + /// + /// This method configures the MVC services for the commonly used features with controllers for an API. This + /// combines the effects of , + /// , + /// , + /// , + /// , + /// and . + /// + /// + /// To add services for controllers with views call + /// on the resulting builder. + /// + /// + /// To add services for pages call + /// on the resulting builder. + /// + /// + public static IMvcBuilder AddControllers(this IServiceCollection services) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + var builder = AddControllersCore(services); + return new MvcBuilder(builder.Services, builder.PartManager); + } + + /// + /// Adds services for controllers to the specified . This method will not + /// register services used for views or pages. + /// + /// The to add services to. + /// An to configure the provided . + /// An that can be used to further configure the MVC services. + /// + /// + /// This method configures the MVC services for the commonly used features with controllers for an API. This + /// combines the effects of , + /// , + /// , + /// , + /// , + /// and . + /// + /// + /// To add services for controllers with views call + /// on the resulting builder. + /// + /// + /// To add services for pages call + /// on the resulting builder. + /// + /// + public static IMvcBuilder AddControllers(this IServiceCollection services, Action configure) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + // This method excludes all of the view-related services by default. + var builder = AddControllersCore(services); + if (configure != null) + { + builder.AddMvcOptions(configure); + } + + return new MvcBuilder(builder.Services, builder.PartManager); + } + + private static IMvcCoreBuilder AddControllersCore(IServiceCollection services) + { + // This method excludes all of the view-related services by default. + return services + .AddMvcCore() + .AddApiExplorer() + .AddAuthorization() + .AddCors() + .AddDataAnnotations() + .AddFormatterMappings(); + } + + /// + /// Adds services for controllers to the specified . This method will not + /// register services used for pages. + /// + /// The to add services to. + /// An that can be used to further configure the MVC services. + /// + /// + /// This method configures the MVC services for the commonly used features with controllers with views. This + /// combines the effects of , + /// , + /// , + /// , + /// , + /// , + /// , + /// , + /// and . + /// + /// + /// To add services for pages call . + /// + /// + public static IMvcBuilder AddControllersWithViews(this IServiceCollection services) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + var builder = AddControllersWithViewsCore(services); + return new MvcBuilder(builder.Services, builder.PartManager); + } + + /// + /// Adds services for controllers to the specified . This method will not + /// register services used for pages. + /// + /// The to add services to. + /// An to configure the provided . + /// An that can be used to further configure the MVC services. + /// + /// + /// This method configures the MVC services for the commonly used features with controllers with views. This + /// combines the effects of , + /// , + /// , + /// , + /// , + /// , + /// , + /// , + /// and . + /// + /// + /// To add services for pages call . + /// + /// + public static IMvcBuilder AddControllersWithViews(this IServiceCollection services, Action configure) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + // This method excludes all of the view-related services by default. + var builder = AddControllersWithViewsCore(services); + if (configure != null) + { + builder.AddMvcOptions(configure); + } + + return new MvcBuilder(builder.Services, builder.PartManager); + } + + private static IMvcCoreBuilder AddControllersWithViewsCore(IServiceCollection services) + { + var builder = AddControllersCore(services).AddViews().AddRazorViewEngine(); + + AddTagHelpersFrameworkParts(builder.PartManager); + + return builder; + } + + /// + /// Adds services for pages to the specified . + /// + /// The to add services to. + /// An that can be used to further configure the MVC services. + /// + /// + /// This method configures the MVC services for the commonly used features for pages. This + /// combines the effects of , + /// , + /// , + /// , + /// and . + /// + /// + /// To add services for controllers for APIs call . + /// + /// + /// To add services for controllers with views call . + /// + /// + public static IMvcBuilder AddRazorPages(this IServiceCollection services) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + var builder = AddRazorPagesCore(services); + return new MvcBuilder(builder.Services, builder.PartManager); + } + + /// + /// Adds services for pages to the specified . + /// + /// The to add services to. + /// An to configure the provided . + /// An that can be used to further configure the MVC services. + /// + /// + /// This method configures the MVC services for the commonly used features for pages. This + /// combines the effects of , + /// , + /// , + /// , + /// and . + /// + /// + /// To add services for controllers for APIs call . + /// + /// + /// To add services for controllers with views call . + /// + /// + public static IMvcBuilder AddRazorPages(this IServiceCollection services, Action configure) + { + if (services == null) + { + throw new ArgumentNullException(nameof(services)); + } + + var builder = AddRazorPagesCore(services); + if (configure != null) + { + builder.AddRazorPages(configure); + } + + return new MvcBuilder(builder.Services, builder.PartManager); + + } + + private static IMvcCoreBuilder AddRazorPagesCore(IServiceCollection services) + { + // This method includes the minimal things controllers need. It's not really feasible to exclude the services + // for controllers. + var builder = services + .AddMvcCore() + .AddAuthorization() + .AddDataAnnotations() + .AddRazorPages() + .AddCacheTagHelper(); + + AddTagHelpersFrameworkParts(builder.PartManager); + + return builder; + } + + internal static void AddTagHelpersFrameworkParts(ApplicationPartManager partManager) + { + var mvcTagHelpersAssembly = typeof(InputTagHelper).GetTypeInfo().Assembly; + if (!partManager.ApplicationParts.OfType().Any(p => p.Assembly == mvcTagHelpersAssembly)) + { + partManager.ApplicationParts.Add(new FrameworkAssemblyPart(mvcTagHelpersAssembly)); + } + + var mvcRazorAssembly = typeof(UrlResolutionTagHelper).GetTypeInfo().Assembly; + if (!partManager.ApplicationParts.OfType().Any(p => p.Assembly == mvcRazorAssembly)) + { + partManager.ApplicationParts.Add(new FrameworkAssemblyPart(mvcRazorAssembly)); + } + } + [DebuggerDisplay("{Name}")] private class FrameworkAssemblyPart : AssemblyPart, ICompilationReferencesProvider { diff --git a/src/Mvc/Mvc/test/MvcServiceCollectionExtensionsTest.cs b/src/Mvc/Mvc/test/MvcServiceCollectionExtensionsTest.cs index aad217683c..c7dadf76b5 100644 --- a/src/Mvc/Mvc/test/MvcServiceCollectionExtensionsTest.cs +++ b/src/Mvc/Mvc/test/MvcServiceCollectionExtensionsTest.cs @@ -17,7 +17,6 @@ using Microsoft.AspNetCore.Mvc.Cors; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Razor; -using Microsoft.AspNetCore.Mvc.Razor.Compilation; using Microsoft.AspNetCore.Mvc.Razor.TagHelpers; using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure; using Microsoft.AspNetCore.Mvc.TagHelpers; @@ -27,11 +26,8 @@ using Microsoft.AspNetCore.Mvc.ViewFeatures.Filters; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.ObjectPool; using Microsoft.Extensions.Options; using Moq; -using Newtonsoft.Json.Serialization; using Xunit; namespace Microsoft.AspNetCore.Mvc @@ -45,23 +41,32 @@ namespace Microsoft.AspNetCore.Mvc // For these kind of multi registration service types, we want to make sure that MVC will still add its // services if the implementation type is different. [Fact] - public void MultiRegistrationServiceTypes_AreRegistered_MultipleTimes() + public void AddMvc_MultiRegistrationServiceTypes_AreRegistered_MultipleTimes() { // Arrange var services = new ServiceCollection(); services.AddSingleton(GetHostingEnvironment()); + RegisterMockMultiRegistrationServices(services); + // Act + services.AddMvc(); + + // Assert + VerifyMultiRegistrationServices(services); + } + + private void RegisterMockMultiRegistrationServices(IServiceCollection services) + { // Register a mock implementation of each service, AddMvcServices should add another implementation. foreach (var serviceType in MultiRegistrationServiceTypes) { var mockType = typeof(Mock<>).MakeGenericType(serviceType.Key); services.Add(ServiceDescriptor.Transient(serviceType.Key, mockType)); } + } - // Act - services.AddMvc(); - - // Assert + private void VerifyMultiRegistrationServices(IServiceCollection services) + { foreach (var serviceType in MultiRegistrationServiceTypes) { AssertServiceCountEquals(services, serviceType.Key, serviceType.Value.Length + 1); @@ -74,23 +79,78 @@ namespace Microsoft.AspNetCore.Mvc } [Fact] - public void SingleRegistrationServiceTypes_AreNotRegistered_MultipleTimes() + public void AddMvc_SingleRegistrationServiceTypes_AreNotRegistered_MultipleTimes() { // Arrange var services = new ServiceCollection(); services.AddSingleton(GetHostingEnvironment()); + RegisterMockSingleRegistrationServices(services); + // Act + services.AddMvc(); + + // Assert + VerifySingleRegistrationServices(services); + } + + [Fact] + public void AddControllers_AddRazorPages_SingleRegistrationServiceTypes_AreNotRegistered_MultipleTimes() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(GetHostingEnvironment()); + RegisterMockSingleRegistrationServices(services); + + // Act + services.AddControllers(); + services.AddRazorPages(); + + // Assert + VerifySingleRegistrationServices(services); + } + + [Fact] + public void AddControllersWithViews_SingleRegistrationServiceTypes_AreNotRegistered_MultipleTimes() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(GetHostingEnvironment()); + RegisterMockSingleRegistrationServices(services); + + // Act + services.AddControllers(); + + // Assert + VerifySingleRegistrationServices(services); + } + + [Fact] + public void AddRazorPages_SingleRegistrationServiceTypes_AreNotRegistered_MultipleTimes() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(GetHostingEnvironment()); + RegisterMockSingleRegistrationServices(services); + + // Act + services.AddRazorPages(); + + // Assert + VerifySingleRegistrationServices(services); + } + + private void RegisterMockSingleRegistrationServices(IServiceCollection services) + { // Register a mock implementation of each service, AddMvcServices should not replace it. foreach (var serviceType in SingleRegistrationServiceTypes) { var mockType = typeof(Mock<>).MakeGenericType(serviceType); services.Add(ServiceDescriptor.Transient(serviceType, mockType)); } + } - // Act - services.AddMvc(); - - // Assert + private void VerifySingleRegistrationServices(IServiceCollection services) + { foreach (var singleRegistrationType in SingleRegistrationServiceTypes) { AssertServiceCountEquals(services, singleRegistrationType, 1); @@ -98,7 +158,7 @@ namespace Microsoft.AspNetCore.Mvc } [Fact] - public void AddMvcServicesTwice_DoesNotAddDuplicates() + public void AddMvc_Twice_DoesNotAddDuplicates() { // Arrange var services = new ServiceCollection(); @@ -109,6 +169,58 @@ namespace Microsoft.AspNetCore.Mvc services.AddMvc(); // Assert + VerifyAllServices(services); + } + + [Fact] + public void AddControllersAddRazorPages_Twice_DoesNotAddDuplicates() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(GetHostingEnvironment()); + + // Act + services.AddControllers(); + services.AddRazorPages(); + services.AddControllers(); + services.AddRazorPages(); + + // Assert + VerifyAllServices(services); + } + + [Fact] + public void AddControllersWithViews_Twice_DoesNotAddDuplicates() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(GetHostingEnvironment()); + + // Act + services.AddControllersWithViews(); + services.AddControllersWithViews(); + + // Assert + VerifyAllServices(services); + } + + [Fact] + public void AddRazorPages_Twice_DoesNotAddDuplicates() + { + // Arrange + var services = new ServiceCollection(); + services.AddSingleton(GetHostingEnvironment()); + + // Act + services.AddRazorPages(); + services.AddRazorPages(); + + // Assert + VerifyAllServices(services); + } + + private void VerifyAllServices(IServiceCollection services) + { var singleRegistrationServiceTypes = SingleRegistrationServiceTypes; foreach (var service in services) { @@ -449,7 +561,8 @@ namespace Microsoft.AspNetCore.Mvc Assert.True( (expectedServiceRegistrationCount == actual), $"Expected service type '{serviceType}' to be registered {expectedServiceRegistrationCount}" + - $" time(s) but was actually registered {actual} time(s)."); + $" time(s) but was actually registered {actual} time(s)." + + string.Join(Environment.NewLine, serviceDescriptors.Select(sd => sd.ImplementationType))); } private void AssertContainsSingle( diff --git a/src/Mvc/test/WebSites/ApiExplorerWebSite/Startup.cs b/src/Mvc/test/WebSites/ApiExplorerWebSite/Startup.cs index ff736bf9c9..e810a1e666 100644 --- a/src/Mvc/test/WebSites/ApiExplorerWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/ApiExplorerWebSite/Startup.cs @@ -22,7 +22,7 @@ namespace ApiExplorerWebSite services.AddTransient(); var wellKnownChangeToken = new WellKnownChangeToken(); - services.AddMvc(options => + services.AddControllers(options => { options.Filters.AddService(typeof(ApiExplorerDataFilter)); diff --git a/src/Mvc/test/WebSites/ApplicationModelWebSite/Startup.cs b/src/Mvc/test/WebSites/ApplicationModelWebSite/Startup.cs index 7d288a4cf5..3c8dab4407 100644 --- a/src/Mvc/test/WebSites/ApplicationModelWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/ApplicationModelWebSite/Startup.cs @@ -14,7 +14,7 @@ namespace ApplicationModelWebSite // Set up application services public void ConfigureServices(IServiceCollection services) { - services.AddMvc(options => + services.AddControllers(options => { options.Conventions.Add(new ApplicationDescription("Common Application Description")); options.Conventions.Add(new ControllerLicenseConvention()); @@ -23,6 +23,8 @@ namespace ApplicationModelWebSite options.Conventions.Add(new CloneActionConvention()); }) .SetCompatibilityVersion(CompatibilityVersion.Latest); + + services.AddRazorPages(); } public void Configure(IApplicationBuilder app) diff --git a/src/Mvc/test/WebSites/ControllersFromServicesWebSite/Startup.cs b/src/Mvc/test/WebSites/ControllersFromServicesWebSite/Startup.cs index 0202fc9f83..910cfd69aa 100644 --- a/src/Mvc/test/WebSites/ControllersFromServicesWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/ControllersFromServicesWebSite/Startup.cs @@ -22,7 +22,7 @@ namespace ControllersFromServicesWebSite public void ConfigureServices(IServiceCollection services) { var builder = services - .AddMvc() + .AddControllersWithViews() .ConfigureApplicationPartManager(manager => manager.ApplicationParts.Clear()) .AddApplicationPart(typeof(TimeScheduleController).GetTypeInfo().Assembly) .ConfigureApplicationPartManager(manager => diff --git a/src/Mvc/test/WebSites/CorsWebSite/Startup.cs b/src/Mvc/test/WebSites/CorsWebSite/Startup.cs index 9c68dc4d62..b8d4d7c727 100644 --- a/src/Mvc/test/WebSites/CorsWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/CorsWebSite/Startup.cs @@ -12,7 +12,7 @@ namespace CorsWebSite { public void ConfigureServices(IServiceCollection services) { - services.AddMvc(ConfigureMvcOptions) + services.AddControllers(ConfigureMvcOptions) .AddNewtonsoftJson() .SetCompatibilityVersion(CompatibilityVersion.Latest); services.Configure(options => diff --git a/src/Mvc/test/WebSites/ErrorPageMiddlewareWebSite/Startup.cs b/src/Mvc/test/WebSites/ErrorPageMiddlewareWebSite/Startup.cs index c5e50c7a71..d8ba0f40d3 100644 --- a/src/Mvc/test/WebSites/ErrorPageMiddlewareWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/ErrorPageMiddlewareWebSite/Startup.cs @@ -14,7 +14,7 @@ namespace ErrorPageMiddlewareWebSite // Set up application services public void ConfigureServices(IServiceCollection services) { - services.AddMvc() + services.AddControllersWithViews() .AddRazorRuntimeCompilation() .SetCompatibilityVersion(CompatibilityVersion.Latest); } diff --git a/src/Mvc/test/WebSites/FilesWebSite/Startup.cs b/src/Mvc/test/WebSites/FilesWebSite/Startup.cs index cd918afa87..518b69212f 100644 --- a/src/Mvc/test/WebSites/FilesWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/FilesWebSite/Startup.cs @@ -14,7 +14,7 @@ namespace FilesWebSite // Set up application services public void ConfigureServices(IServiceCollection services) { - services.AddMvc() + services.AddControllers() .AddNewtonsoftJson() .SetCompatibilityVersion(CompatibilityVersion.Latest); } diff --git a/src/Mvc/test/WebSites/FormatterWebSite/Startup.cs b/src/Mvc/test/WebSites/FormatterWebSite/Startup.cs index 603e7dc618..ba036d9a08 100644 --- a/src/Mvc/test/WebSites/FormatterWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/FormatterWebSite/Startup.cs @@ -12,7 +12,7 @@ namespace FormatterWebSite { public void ConfigureServices(IServiceCollection services) { - services.AddMvc(options => + services.AddControllers(options => { options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(Developer))); options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(Supplier))); diff --git a/src/Mvc/test/WebSites/FormatterWebSite/StartupWithRespectBrowserAcceptHeader.cs b/src/Mvc/test/WebSites/FormatterWebSite/StartupWithRespectBrowserAcceptHeader.cs index 9614f491f7..5459a54b36 100644 --- a/src/Mvc/test/WebSites/FormatterWebSite/StartupWithRespectBrowserAcceptHeader.cs +++ b/src/Mvc/test/WebSites/FormatterWebSite/StartupWithRespectBrowserAcceptHeader.cs @@ -10,7 +10,7 @@ namespace FormatterWebSite { public void ConfigureServices(IServiceCollection services) { - services.AddMvc(options => + services.AddControllers(options => { options.RespectBrowserAcceptHeader = true; }) diff --git a/src/Mvc/test/WebSites/GenericHostWebSite/Startup.cs b/src/Mvc/test/WebSites/GenericHostWebSite/Startup.cs index cb2ce81b4a..055adbe13b 100644 --- a/src/Mvc/test/WebSites/GenericHostWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/GenericHostWebSite/Startup.cs @@ -19,7 +19,7 @@ namespace GenericHostWebSite services.AddSingleton(new TestGenericService { Message = "true" }); services - .AddMvc(options => + .AddControllers(options => { // Remove when all URL generation tests are passing - https://github.com/aspnet/Routing/issues/590 options.EnableEndpointRouting = false; diff --git a/src/Mvc/test/WebSites/RazorPagesWebSite/Startup.cs b/src/Mvc/test/WebSites/RazorPagesWebSite/Startup.cs index f8bb11a78c..e75ac2f1ab 100644 --- a/src/Mvc/test/WebSites/RazorPagesWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/RazorPagesWebSite/Startup.cs @@ -15,8 +15,7 @@ namespace RazorPagesWebSite services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => options.LoginPath = "/Login"); - services.AddMvc() - .AddRazorPagesOptions(options => + services.AddRazorPages(options => { options.Conventions.AuthorizeFolder("/Admin"); }) diff --git a/src/Mvc/test/WebSites/SecurityWebSite/Startup.cs b/src/Mvc/test/WebSites/SecurityWebSite/Startup.cs index 0e26a546c2..93bae9b71f 100644 --- a/src/Mvc/test/WebSites/SecurityWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/SecurityWebSite/Startup.cs @@ -15,8 +15,7 @@ namespace SecurityWebSite public void ConfigureServices(IServiceCollection services) { // Add framework services. - services.AddMvc() - .SetCompatibilityVersion(CompatibilityVersion.Latest); + services.AddControllersWithViews().SetCompatibilityVersion(CompatibilityVersion.Latest); services.AddAntiforgery(); services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options => { diff --git a/src/Mvc/test/WebSites/TagHelpersWebSite/Startup.cs b/src/Mvc/test/WebSites/TagHelpersWebSite/Startup.cs index f01dac0414..f7caea4035 100644 --- a/src/Mvc/test/WebSites/TagHelpersWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/TagHelpersWebSite/Startup.cs @@ -14,7 +14,7 @@ namespace TagHelpersWebSite // Set up application services public void ConfigureServices(IServiceCollection services) { - services.AddMvc() + services.AddControllersWithViews() .SetCompatibilityVersion(CompatibilityVersion.Latest); } diff --git a/src/Mvc/test/WebSites/VersioningWebSite/Startup.cs b/src/Mvc/test/WebSites/VersioningWebSite/Startup.cs index 0314094df8..88510f4a9e 100644 --- a/src/Mvc/test/WebSites/VersioningWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/VersioningWebSite/Startup.cs @@ -12,8 +12,7 @@ namespace VersioningWebSite { public void ConfigureServices(IServiceCollection services) { - // Add MVC services to the services container - services.AddMvc(ConfigureMvcOptions) + services.AddControllers(ConfigureMvcOptions) .AddNewtonsoftJson() .SetCompatibilityVersion(CompatibilityVersion.Latest); diff --git a/src/Mvc/test/WebSites/XmlFormattersWebSite/Startup.cs b/src/Mvc/test/WebSites/XmlFormattersWebSite/Startup.cs index 0e45dec94a..10466f26c7 100644 --- a/src/Mvc/test/WebSites/XmlFormattersWebSite/Startup.cs +++ b/src/Mvc/test/WebSites/XmlFormattersWebSite/Startup.cs @@ -19,7 +19,7 @@ namespace XmlFormattersWebSite public void ConfigureServices(IServiceCollection services) { // Add MVC services to the services container - services.AddMvc() + services.AddControllers() .AddXmlDataContractSerializerFormatters() .AddXmlSerializerFormatters() .SetCompatibilityVersion(CompatibilityVersion); diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorComponentsWeb-CSharp/Startup.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorComponentsWeb-CSharp/Startup.cs index a250f47e74..9bf1044b02 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorComponentsWeb-CSharp/Startup.cs +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorComponentsWeb-CSharp/Startup.cs @@ -20,7 +20,7 @@ namespace RazorComponentsWeb_CSharp // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { - services.AddMvc() + services.AddRazorPages() .AddNewtonsoftJson(); services.AddRazorComponents(); diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/Startup.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/Startup.cs index 3f407be714..26d359acc7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/Startup.cs +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/Startup.cs @@ -119,7 +119,7 @@ namespace Company.WebApplication1 #endif #if (OrganizationalAuth) - services.AddMvc(options => + services.AddRazorPages().AddMvcOptions(options => { var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() @@ -128,7 +128,7 @@ namespace Company.WebApplication1 }) .AddNewtonsoftJson(); #else - services.AddMvc() + services.AddRazorPages() .AddNewtonsoftJson(); #endif } diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/Startup.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/Startup.cs index c6611407b5..5e1291823e 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/Startup.cs +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/Startup.cs @@ -118,7 +118,7 @@ namespace Company.WebApplication1 #endif #if (OrganizationalAuth) - services.AddMvc(options => + services.AddControllersWithViews(options => { var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() @@ -127,9 +127,10 @@ namespace Company.WebApplication1 }) .AddNewtonsoftJson(); #else - services.AddMvc() + services.AddControllersWithViews() .AddNewtonsoftJson(); #endif + services.AddRazorPages(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-FSharp/Startup.fs b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-FSharp/Startup.fs index fa65fda3f5..91d078759a 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-FSharp/Startup.fs +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-FSharp/Startup.fs @@ -22,7 +22,8 @@ type Startup private () = // This method gets called by the runtime. Use this method to add services to the container. member this.ConfigureServices(services: IServiceCollection) = // Add framework services. - services.AddMvc().AddNewtonsoftJson().AddRazorRuntimeCompilation() |> ignore + services.AddControllersWithViews().AddNewtonsoftJson().AddRazorRuntimeCompilation() |> ignore + services.AddRazorPages() |> ignore // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. member this.Configure(app: IApplicationBuilder, env: IWebHostEnvironment) = diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Startup.cs b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Startup.cs index 987d2d282b..3088897131 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Startup.cs +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-CSharp/Startup.cs @@ -44,7 +44,7 @@ namespace Company.WebApplication1 services.AddAuthentication(AzureADB2CDefaults.BearerAuthenticationScheme) .AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options)); #endif - services.AddMvc() + services.AddControllers() .AddNewtonsoftJson(); } diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-FSharp/Startup.fs b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-FSharp/Startup.fs index 55ed03b223..3df5e59353 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-FSharp/Startup.fs +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/WebApi-FSharp/Startup.fs @@ -22,7 +22,7 @@ type Startup private () = // This method gets called by the runtime. Use this method to add services to the container. member this.ConfigureServices(services: IServiceCollection) = // Add framework services. - services.AddMvc().AddNewtonsoftJson() |> ignore + services.AddControllers().AddNewtonsoftJson() |> ignore // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. member this.Configure(app: IApplicationBuilder, env: IWebHostEnvironment) =