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:
Ryan Nowak 2019-03-07 18:13:02 -08:00
parent 0cfac5b88d
commit 284e968101
39 changed files with 564 additions and 110 deletions

View File

@ -450,7 +450,7 @@ namespace Microsoft.AspNetCore.Builder
{
throw new InvalidOperationException(Resources.FormatUnableToFindServices(
nameof(IServiceCollection),
"AddMvc",
"AddControllers",
"ConfigureServices(...)"));
}
}

View File

@ -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());
}
}

View File

@ -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")]

View File

@ -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(...)"));
}
}

View File

@ -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(

View File

@ -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")]

View File

@ -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>();
}
}
}

View File

@ -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")]

View File

@ -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())
{

View File

@ -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);
}
}

View File

@ -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")]

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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()
{

View File

@ -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()
{

View File

@ -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()
{

View File

@ -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; }
}
}

View File

@ -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
{

View File

@ -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(

View File

@ -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));

View File

@ -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)

View File

@ -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 =>

View File

@ -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 =>

View File

@ -14,7 +14,7 @@ namespace ErrorPageMiddlewareWebSite
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
services.AddControllersWithViews()
.AddRazorRuntimeCompilation()
.SetCompatibilityVersion(CompatibilityVersion.Latest);
}

View File

@ -14,7 +14,7 @@ namespace FilesWebSite
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
services.AddControllers()
.AddNewtonsoftJson()
.SetCompatibilityVersion(CompatibilityVersion.Latest);
}

View File

@ -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)));

View File

@ -10,7 +10,7 @@ namespace FormatterWebSite
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
services.AddControllers(options =>
{
options.RespectBrowserAcceptHeader = true;
})

View File

@ -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;

View File

@ -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");
})

View File

@ -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 =>
{

View File

@ -14,7 +14,7 @@ namespace TagHelpersWebSite
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
services.AddControllersWithViews()
.SetCompatibilityVersion(CompatibilityVersion.Latest);
}

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -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
}

View File

@ -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.

View File

@ -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) =

View File

@ -44,7 +44,7 @@ namespace Company.WebApplication1
services.AddAuthentication(AzureADB2CDefaults.BearerAuthenticationScheme)
.AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));
#endif
services.AddMvc()
services.AddControllers()
.AddNewtonsoftJson();
}

View File

@ -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) =