Add AddControllers and AddRazorPages
These are *new style* for configuring MVC in services. We're adding these to make things feel a bit more tailored to those particular scenarios. ---- The main reason for this is that we've had repeated community asks for an *API-optimized* way of configuring MVC. I don't think that using AddMvcCore is a suitable building block, because it has too many options that you want. I've think I've identified the reasonable set of features that should be part of the default experience for APIs. All of these things are already pay-for-play and are activated by the presence of attributes. The only additional cost is loading of assemblies and a few additional inspections of the attributes (cached). ---- Additionally the AddControllers experience is composible. You can add views to it, or add pages and get the whole thing. AddRazorPages is basically an alias for what AddMvc does today. We don't currently have a way to add pages without controllers (the opposite is true). Based on feedback we could specialize this more. ---- Branding and perception are important, and we've users ask for more flexibility in what gets added. The plan is to update the templates to use this experience in preview4, and see what kind of feedback we get.
This commit is contained in:
parent
0cfac5b88d
commit
284e968101
|
|
@ -450,7 +450,7 @@ namespace Microsoft.AspNetCore.Builder
|
|||
{
|
||||
throw new InvalidOperationException(Resources.FormatUnableToFindServices(
|
||||
nameof(IServiceCollection),
|
||||
"AddMvc",
|
||||
"AddControllers",
|
||||
"ConfigureServices(...)"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<TagHelperFeatureProvider>().Any())
|
||||
if (!partManager.FeatureProviders.OfType<TagHelperFeatureProvider>().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<RazorCompiledItemFeatureProvider>().Any())
|
||||
if (!partManager.FeatureProviders.OfType<RazorCompiledItemFeatureProvider>().Any())
|
||||
{
|
||||
builder.PartManager.FeatureProviders.Add(new RazorCompiledItemFeatureProvider());
|
||||
partManager.FeatureProviders.Add(new RazorCompiledItemFeatureProvider());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.Builder
|
|||
/// <para>
|
||||
/// <see cref="MapFallbackToPage(IEndpointRouteBuilder, string)"/> does not re-execute routing, and will
|
||||
/// not generate route values based on routes defined elsewhere. When using this overload, the <c>path</c> route value
|
||||
/// will be available.
|
||||
/// will be available.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
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
|
|||
/// </para>
|
||||
/// <para>
|
||||
/// <see cref="MapFallbackToPage(IEndpointRouteBuilder, string, string)"/> 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
|
||||
/// <paramref name="pattern"/> will be available.
|
||||
/// not generate route values based on routes defined elsewhere. When using this overload, the route values provided by matching
|
||||
/// <paramref name="pattern"/> will be available.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
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
|
|||
/// <para>
|
||||
/// <see cref="MapFallbackToAreaPage(IEndpointRouteBuilder, string, string)"/> does not re-execute routing, and will
|
||||
/// not generate route values based on routes defined elsewhere. When using this overload, the <c>path</c> route value
|
||||
/// will be available.
|
||||
/// will be available.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
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
|
|||
/// </para>
|
||||
/// <para>
|
||||
/// <see cref="MapFallbackToAreaPage(IEndpointRouteBuilder, string, string, string)"/> 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
|
||||
/// <paramref name="pattern"/> will be available.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
|
|
@ -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(...)"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -25,13 +25,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
builder.Services.TryAddSingleton<IDistributedCacheTagHelperStorage, DistributedCacheTagHelperStorage>();
|
||||
builder.Services.TryAddSingleton<IDistributedCacheTagHelperFormatter, DistributedCacheTagHelperFormatter>();
|
||||
builder.Services.TryAddSingleton<IDistributedCacheTagHelperService, DistributedCacheTagHelperService>();
|
||||
|
||||
// Required default services for cache tag helpers
|
||||
builder.Services.AddDistributedMemoryCache();
|
||||
builder.Services.TryAddSingleton<CacheTagHelperMemoryCacheFactory>();
|
||||
AddCacheTagHelperServices(builder.Services);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
|
@ -81,5 +75,16 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
|
||||
return builder;
|
||||
}
|
||||
|
||||
internal static void AddCacheTagHelperServices(IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<IDistributedCacheTagHelperStorage, DistributedCacheTagHelperStorage>();
|
||||
services.TryAddSingleton<IDistributedCacheTagHelperFormatter, DistributedCacheTagHelperFormatter>();
|
||||
services.TryAddSingleton<IDistributedCacheTagHelperService, DistributedCacheTagHelperService>();
|
||||
|
||||
// Required default services for cache tag helpers
|
||||
services.AddDistributedMemoryCache();
|
||||
services.TryAddSingleton<CacheTagHelperMemoryCacheFactory>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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<ViewComponentFeatureProvider>().Any())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -65,7 +65,15 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
}
|
||||
|
||||
var services = context.HttpContext.RequestServices;
|
||||
var executor = services.GetRequiredService<IActionResultExecutor<PartialViewResult>>();
|
||||
var executor = services.GetService<IActionResultExecutor<PartialViewResult>>();
|
||||
if (executor == null)
|
||||
{
|
||||
throw new InvalidOperationException(Mvc.Core.Resources.FormatUnableToFindServices(
|
||||
nameof(IServiceCollection),
|
||||
"AddControllersWithViews()",
|
||||
"ConfigureServices(...)"));
|
||||
}
|
||||
|
||||
return executor.ExecuteAsync(context, this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -64,7 +64,15 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
}
|
||||
|
||||
var services = context.HttpContext.RequestServices;
|
||||
var executor = services.GetRequiredService<IActionResultExecutor<ViewComponentResult>>();
|
||||
var executor = services.GetService<IActionResultExecutor<ViewComponentResult>>();
|
||||
if (executor == null)
|
||||
{
|
||||
throw new InvalidOperationException(Mvc.Core.Resources.FormatUnableToFindServices(
|
||||
nameof(IServiceCollection),
|
||||
"AddControllersWithViews()",
|
||||
"ConfigureServices(...)"));
|
||||
}
|
||||
|
||||
return executor.ExecuteAsync(context, this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,15 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var executor = context.HttpContext.RequestServices.GetRequiredService<IActionResultExecutor<ViewResult>>();
|
||||
var executor = context.HttpContext.RequestServices.GetService<IActionResultExecutor<ViewResult>>();
|
||||
if (executor == null)
|
||||
{
|
||||
throw new InvalidOperationException(Mvc.Core.Resources.FormatUnableToFindServices(
|
||||
nameof(IServiceCollection),
|
||||
"AddControllersWithViews()",
|
||||
"ConfigureServices(...)"));
|
||||
}
|
||||
|
||||
await executor.ExecuteAsync(context, this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<IServiceProvider>(), }, 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<InvalidOperationException>(() => viewResult.ExecuteResultAsync(actionContext));
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_Throws_IfViewCouldNotBeFound_MessageUsesGetViewLocations()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<IServiceProvider>(), }, 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<InvalidOperationException>(() => viewResult.ExecuteResultAsync(actionContext));
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_ViewComponentResult_AllowsNullViewDataAndTempData()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<IServiceProvider>(), }, 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<InvalidOperationException>(() => viewResult.ExecuteResultAsync(actionContext));
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_Throws_IfViewCouldNotBeFound_MessageUsesGetViewLocations()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<Microsoft.AspNetCore.Mvc.MvcOptions> 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<Microsoft.AspNetCore.Mvc.MvcOptions> 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<Microsoft.AspNetCore.Mvc.MvcOptions> 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<Microsoft.AspNetCore.Mvc.RazorPages.RazorPagesOptions> configure) { throw null; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<AssemblyPart>().Any(p => p.Assembly == mvcTagHelpersAssembly))
|
||||
{
|
||||
partManager.ApplicationParts.Add(new FrameworkAssemblyPart(mvcTagHelpersAssembly));
|
||||
}
|
||||
|
||||
var mvcRazorAssembly = typeof(UrlResolutionTagHelper).GetTypeInfo().Assembly;
|
||||
if (!partManager.ApplicationParts.OfType<AssemblyPart>().Any(p => p.Assembly == mvcRazorAssembly))
|
||||
{
|
||||
partManager.ApplicationParts.Add(new FrameworkAssemblyPart(mvcRazorAssembly));
|
||||
}
|
||||
services.AddControllersWithViews();
|
||||
return services.AddRazorPages();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -93,6 +59,283 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds services for controllers to the specified <see cref="IServiceCollection"/>. This method will not
|
||||
/// register services used for views or pages.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
|
||||
/// <returns>An <see cref="IMvcBuilder"/> that can be used to further configure the MVC services.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method configures the MVC services for the commonly used features with controllers for an API. This
|
||||
/// combines the effects of <see cref="MvcCoreServiceCollectionExtensions.AddMvcCore(IServiceCollection)"/>,
|
||||
/// <see cref="MvcApiExplorerMvcCoreBuilderExtensions.AddApiExplorer(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcCoreMvcCoreBuilderExtensions.AddAuthorization(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcCorsMvcCoreBuilderExtensions.AddCors(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcDataAnnotationsMvcCoreBuilderExtensions.AddDataAnnotations(IMvcCoreBuilder)"/>,
|
||||
/// and <see cref="MvcCoreMvcCoreBuilderExtensions.AddFormatterMappings(IMvcCoreBuilder)"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// To add services for controllers with views call <see cref="AddControllersWithViews(IServiceCollection)"/>
|
||||
/// on the resulting builder.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// To add services for pages call <see cref="AddRazorPages(IServiceCollection)"/>
|
||||
/// on the resulting builder.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds services for controllers to the specified <see cref="IServiceCollection"/>. This method will not
|
||||
/// register services used for views or pages.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
|
||||
/// <param name="configure">An <see cref="Action{MvcOptions}"/> to configure the provided <see cref="MvcOptions"/>.</param>
|
||||
/// <returns>An <see cref="IMvcBuilder"/> that can be used to further configure the MVC services.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method configures the MVC services for the commonly used features with controllers for an API. This
|
||||
/// combines the effects of <see cref="MvcCoreServiceCollectionExtensions.AddMvcCore(IServiceCollection)"/>,
|
||||
/// <see cref="MvcApiExplorerMvcCoreBuilderExtensions.AddApiExplorer(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcCoreMvcCoreBuilderExtensions.AddAuthorization(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcCorsMvcCoreBuilderExtensions.AddCors(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcDataAnnotationsMvcCoreBuilderExtensions.AddDataAnnotations(IMvcCoreBuilder)"/>,
|
||||
/// and <see cref="MvcCoreMvcCoreBuilderExtensions.AddFormatterMappings(IMvcCoreBuilder)"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// To add services for controllers with views call <see cref="AddControllersWithViews(IServiceCollection)"/>
|
||||
/// on the resulting builder.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// To add services for pages call <see cref="AddRazorPages(IServiceCollection)"/>
|
||||
/// on the resulting builder.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static IMvcBuilder AddControllers(this IServiceCollection services, Action<MvcOptions> 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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds services for controllers to the specified <see cref="IServiceCollection"/>. This method will not
|
||||
/// register services used for pages.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
|
||||
/// <returns>An <see cref="IMvcBuilder"/> that can be used to further configure the MVC services.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method configures the MVC services for the commonly used features with controllers with views. This
|
||||
/// combines the effects of <see cref="MvcCoreServiceCollectionExtensions.AddMvcCore(IServiceCollection)"/>,
|
||||
/// <see cref="MvcApiExplorerMvcCoreBuilderExtensions.AddApiExplorer(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcCoreMvcCoreBuilderExtensions.AddAuthorization(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcCorsMvcCoreBuilderExtensions.AddCors(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcDataAnnotationsMvcCoreBuilderExtensions.AddDataAnnotations(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcCoreMvcCoreBuilderExtensions.AddFormatterMappings(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="TagHelperServicesExtensions.AddCacheTagHelper(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcViewFeaturesMvcCoreBuilderExtensions.AddViews(IMvcCoreBuilder)"/>,
|
||||
/// and <see cref="MvcRazorMvcCoreBuilderExtensions.AddRazorViewEngine(IMvcCoreBuilder)"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// To add services for pages call <see cref="AddRazorPages(IServiceCollection)"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds services for controllers to the specified <see cref="IServiceCollection"/>. This method will not
|
||||
/// register services used for pages.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
|
||||
/// <param name="configure">An <see cref="Action{MvcOptions}"/> to configure the provided <see cref="MvcOptions"/>.</param>
|
||||
/// <returns>An <see cref="IMvcBuilder"/> that can be used to further configure the MVC services.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method configures the MVC services for the commonly used features with controllers with views. This
|
||||
/// combines the effects of <see cref="MvcCoreServiceCollectionExtensions.AddMvcCore(IServiceCollection)"/>,
|
||||
/// <see cref="MvcApiExplorerMvcCoreBuilderExtensions.AddApiExplorer(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcCoreMvcCoreBuilderExtensions.AddAuthorization(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcCorsMvcCoreBuilderExtensions.AddCors(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcDataAnnotationsMvcCoreBuilderExtensions.AddDataAnnotations(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcCoreMvcCoreBuilderExtensions.AddFormatterMappings(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="TagHelperServicesExtensions.AddCacheTagHelper(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcViewFeaturesMvcCoreBuilderExtensions.AddViews(IMvcCoreBuilder)"/>,
|
||||
/// and <see cref="MvcRazorMvcCoreBuilderExtensions.AddRazorViewEngine(IMvcCoreBuilder)"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// To add services for pages call <see cref="AddRazorPages(IServiceCollection)"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static IMvcBuilder AddControllersWithViews(this IServiceCollection services, Action<MvcOptions> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds services for pages to the specified <see cref="IServiceCollection"/>.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
|
||||
/// <returns>An <see cref="IMvcBuilder"/> that can be used to further configure the MVC services.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method configures the MVC services for the commonly used features for pages. This
|
||||
/// combines the effects of <see cref="MvcCoreServiceCollectionExtensions.AddMvcCore(IServiceCollection)"/>,
|
||||
/// <see cref="MvcCoreMvcCoreBuilderExtensions.AddAuthorization(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcDataAnnotationsMvcCoreBuilderExtensions.AddDataAnnotations(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="TagHelperServicesExtensions.AddCacheTagHelper(IMvcCoreBuilder)"/>,
|
||||
/// and <see cref="MvcRazorPagesMvcCoreBuilderExtensions.AddRazorPages(IMvcCoreBuilder)"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// To add services for controllers for APIs call <see cref="AddControllers(IServiceCollection)"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// To add services for controllers with views call <see cref="AddControllersWithViews(IServiceCollection)"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds services for pages to the specified <see cref="IServiceCollection"/>.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
|
||||
/// <param name="configure">An <see cref="Action{MvcOptions}"/> to configure the provided <see cref="MvcOptions"/>.</param>
|
||||
/// <returns>An <see cref="IMvcBuilder"/> that can be used to further configure the MVC services.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method configures the MVC services for the commonly used features for pages. This
|
||||
/// combines the effects of <see cref="MvcCoreServiceCollectionExtensions.AddMvcCore(IServiceCollection)"/>,
|
||||
/// <see cref="MvcCoreMvcCoreBuilderExtensions.AddAuthorization(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="MvcDataAnnotationsMvcCoreBuilderExtensions.AddDataAnnotations(IMvcCoreBuilder)"/>,
|
||||
/// <see cref="TagHelperServicesExtensions.AddCacheTagHelper(IMvcCoreBuilder)"/>,
|
||||
/// and <see cref="MvcRazorPagesMvcCoreBuilderExtensions.AddRazorPages(IMvcCoreBuilder)"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// To add services for controllers for APIs call <see cref="AddControllers(IServiceCollection)"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// To add services for controllers with views call <see cref="AddControllersWithViews(IServiceCollection)"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static IMvcBuilder AddRazorPages(this IServiceCollection services, Action<RazorPagesOptions> 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<AssemblyPart>().Any(p => p.Assembly == mvcTagHelpersAssembly))
|
||||
{
|
||||
partManager.ApplicationParts.Add(new FrameworkAssemblyPart(mvcTagHelpersAssembly));
|
||||
}
|
||||
|
||||
var mvcRazorAssembly = typeof(UrlResolutionTagHelper).GetTypeInfo().Assembly;
|
||||
if (!partManager.ApplicationParts.OfType<AssemblyPart>().Any(p => p.Assembly == mvcRazorAssembly))
|
||||
{
|
||||
partManager.ApplicationParts.Add(new FrameworkAssemblyPart(mvcRazorAssembly));
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerDisplay("{Name}")]
|
||||
private class FrameworkAssemblyPart : AssemblyPart, ICompilationReferencesProvider
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<IWebHostEnvironment>(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<IWebHostEnvironment>(GetHostingEnvironment());
|
||||
RegisterMockSingleRegistrationServices(services);
|
||||
|
||||
// Act
|
||||
services.AddMvc();
|
||||
|
||||
// Assert
|
||||
VerifySingleRegistrationServices(services);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddControllers_AddRazorPages_SingleRegistrationServiceTypes_AreNotRegistered_MultipleTimes()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton<IWebHostEnvironment>(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<IWebHostEnvironment>(GetHostingEnvironment());
|
||||
RegisterMockSingleRegistrationServices(services);
|
||||
|
||||
// Act
|
||||
services.AddControllers();
|
||||
|
||||
// Assert
|
||||
VerifySingleRegistrationServices(services);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddRazorPages_SingleRegistrationServiceTypes_AreNotRegistered_MultipleTimes()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton<IWebHostEnvironment>(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<IWebHostEnvironment>(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<IWebHostEnvironment>(GetHostingEnvironment());
|
||||
|
||||
// Act
|
||||
services.AddControllersWithViews();
|
||||
services.AddControllersWithViews();
|
||||
|
||||
// Assert
|
||||
VerifyAllServices(services);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddRazorPages_Twice_DoesNotAddDuplicates()
|
||||
{
|
||||
// Arrange
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton<IWebHostEnvironment>(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(
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace ApiExplorerWebSite
|
|||
services.AddTransient<ILoggerFactory, LoggerFactory>();
|
||||
|
||||
var wellKnownChangeToken = new WellKnownChangeToken();
|
||||
services.AddMvc(options =>
|
||||
services.AddControllers(options =>
|
||||
{
|
||||
options.Filters.AddService(typeof(ApiExplorerDataFilter));
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 =>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace CorsWebSite
|
|||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMvc(ConfigureMvcOptions)
|
||||
services.AddControllers(ConfigureMvcOptions)
|
||||
.AddNewtonsoftJson()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Latest);
|
||||
services.Configure<CorsOptions>(options =>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace ErrorPageMiddlewareWebSite
|
|||
// Set up application services
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMvc()
|
||||
services.AddControllersWithViews()
|
||||
.AddRazorRuntimeCompilation()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Latest);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace FilesWebSite
|
|||
// Set up application services
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMvc()
|
||||
services.AddControllers()
|
||||
.AddNewtonsoftJson()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Latest);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace FormatterWebSite
|
|||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMvc(options =>
|
||||
services.AddControllers(options =>
|
||||
{
|
||||
options.RespectBrowserAcceptHeader = true;
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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 =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace TagHelpersWebSite
|
|||
// Set up application services
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMvc()
|
||||
services.AddControllersWithViews()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Latest);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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) =
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ namespace Company.WebApplication1
|
|||
services.AddAuthentication(AzureADB2CDefaults.BearerAuthenticationScheme)
|
||||
.AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));
|
||||
#endif
|
||||
services.AddMvc()
|
||||
services.AddControllers()
|
||||
.AddNewtonsoftJson();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) =
|
||||
|
|
|
|||
Loading…
Reference in New Issue