Homogenize MVC startup code patterns

Use builder APIS for both AddMvc() and AddMvcCore()
Change various API patterns to all use .AddXyz(...) off of one or both of
these builders.
This commit is contained in:
Ryan Nowak 2015-08-13 18:17:41 -07:00
parent dac75fa56d
commit 9d89a8cac3
52 changed files with 983 additions and 785 deletions

View File

@ -25,19 +25,18 @@ namespace MvcSample.Web
services.AddCaching();
services.AddSession();
services.AddMvc();
services.AddMvc(options =>
{
options.Filters.Add(typeof(PassThroughAttribute), order: 17);
options.Filters.Add(new FormatFilterAttribute());
})
.AddXmlDataContractSerializerFormatters()
.AddViewLocalization(LanguageViewLocationExpanderFormat.SubFolder);
services.AddSingleton<PassThroughAttribute>();
services.AddSingleton<UserNameService>();
services.AddTransient<ITestService, TestService>();
services.ConfigureMvc(options =>
{
options.Filters.Add(typeof(PassThroughAttribute), order: 17);
options.AddXmlDataContractSerializerFormatter();
options.Filters.Add(new FormatFilterAttribute());
});
services.AddMvcLocalization(LanguageViewLocationExpanderFormat.SubFolder);
var applicationEnvironment = services.BuildServiceProvider().GetRequiredService<IApplicationEnvironment>();
var configurationPath = Path.Combine(applicationEnvironment.ApplicationBasePath, "config.json");

View File

@ -7,9 +7,9 @@ using Microsoft.Framework.Internal;
namespace Microsoft.Framework.DependencyInjection
{
public static class MvcApiExplorerMvcBuilderExtensions
public static class MvcApiExplorerMvcCoreBuilderExtensions
{
public static IMvcBuilder AddApiExplorer([NotNull] this IMvcBuilder builder)
public static IMvcCoreBuilder AddApiExplorer([NotNull] this IMvcCoreBuilder builder)
{
AddApiExplorerServices(builder.Services);
return builder;

View File

@ -0,0 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.Framework.DependencyInjection
{
public interface IMvcCoreBuilder
{
IServiceCollection Services { get; }
}
}

View File

@ -2,66 +2,56 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Authorization;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ApplicationModels;
using Microsoft.Framework.DependencyInjection.Extensions;
using Microsoft.AspNet.Mvc.Internal;
using Microsoft.Framework.Internal;
namespace Microsoft.Framework.DependencyInjection
{
/// <summary>
/// Extensions for configuring MVC using an <see cref="IMvcBuilder"/>.
/// </summary>
public static class MvcCoreMvcBuilderExtensions
{
public static IMvcBuilder AddFormatterMappings(this IMvcBuilder builder)
{
AddFormatterMappingsServices(builder.Services);
return builder;
}
public static IMvcBuilder AddFormatterMappings(
this IMvcBuilder builder,
Action<FormatterMappings> setupAction)
[NotNull] this IMvcBuilder builder,
[NotNull] Action<FormatterMappings> setupAction)
{
AddFormatterMappingsServices(builder.Services);
if (setupAction != null)
{
builder.Services.Configure<MvcOptions>((options) => setupAction(options.FormatterMappings));
}
builder.Services.Configure<MvcOptions>((options) => setupAction(options.FormatterMappings));
return builder;
}
// Internal for testing.
internal static void AddFormatterMappingsServices(IServiceCollection services)
/// <summary>
/// Register the specified <paramref name="controllerTypes"/> as services and as a source for controller
/// discovery.
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <param name="controllerTypes">A sequence of controller <see cref="Type"/>s to register in the
/// <paramref name="services"/> and used for controller discovery.</param>
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
public static IMvcBuilder AddControllersAsServices(
[NotNull] this IMvcBuilder builder,
[NotNull] IEnumerable<Type> controllerTypes)
{
services.TryAddTransient<FormatFilter, FormatFilter>();
}
public static IMvcBuilder AddAuthorization(this IMvcBuilder builder)
{
AddAuthorizationServices(builder.Services);
ControllersAsServices.AddControllersAsServices(builder.Services, controllerTypes);
return builder;
}
public static IMvcBuilder AddAuthorization(this IMvcBuilder builder, Action<AuthorizationOptions> setupAction)
/// <summary>
/// Registers controller types from the specified <paramref name="assemblies"/> as services and as a source
/// for controller discovery.
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <param name="controllerAssemblies">Assemblies to scan.</param>
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
public static IMvcBuilder AddControllersAsServices(
[NotNull] this IMvcBuilder builder,
[NotNull] IEnumerable<Assembly> controllerAssemblies)
{
AddAuthorizationServices(builder.Services);
if (setupAction != null)
{
builder.Services.Configure(setupAction);
}
ControllersAsServices.AddControllersAsServices(builder.Services, controllerAssemblies);
return builder;
}
// Internal for testing.
internal static void AddAuthorizationServices(IServiceCollection services)
{
services.AddAuthorization();
services.TryAddEnumerable(
ServiceDescriptor.Transient<IApplicationModelProvider, AuthorizationApplicationModelProvider>());
}
}
}

View File

@ -0,0 +1,104 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNet.Authorization;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ApplicationModels;
using Microsoft.AspNet.Mvc.Internal;
using Microsoft.Framework.DependencyInjection.Extensions;
using Microsoft.Framework.Internal;
namespace Microsoft.Framework.DependencyInjection
{
public static class MvcCoreMvcCoreBuilderExtensions
{
public static IMvcCoreBuilder AddFormatterMappings(this IMvcCoreBuilder builder)
{
AddFormatterMappingsServices(builder.Services);
return builder;
}
public static IMvcCoreBuilder AddFormatterMappings(
this IMvcCoreBuilder builder,
Action<FormatterMappings> setupAction)
{
AddFormatterMappingsServices(builder.Services);
if (setupAction != null)
{
builder.Services.Configure<MvcOptions>((options) => setupAction(options.FormatterMappings));
}
return builder;
}
// Internal for testing.
internal static void AddFormatterMappingsServices(IServiceCollection services)
{
services.TryAddTransient<FormatFilter, FormatFilter>();
}
public static IMvcCoreBuilder AddAuthorization(this IMvcCoreBuilder builder)
{
AddAuthorizationServices(builder.Services);
return builder;
}
public static IMvcCoreBuilder AddAuthorization(
this IMvcCoreBuilder builder,
Action<AuthorizationOptions> setupAction)
{
AddAuthorizationServices(builder.Services);
if (setupAction != null)
{
builder.Services.Configure(setupAction);
}
return builder;
}
// Internal for testing.
internal static void AddAuthorizationServices(IServiceCollection services)
{
services.AddAuthorization();
services.TryAddEnumerable(
ServiceDescriptor.Transient<IApplicationModelProvider, AuthorizationApplicationModelProvider>());
}
/// <summary>
/// Register the specified <paramref name="controllerTypes"/> as services and as a source for controller
/// discovery.
/// </summary>
/// <param name="builder">The <see cref="IMvcCoreBuilder"/>.</param>
/// <param name="controllerTypes">A sequence of controller <see cref="Type"/>s to register in the
/// <paramref name="services"/> and used for controller discovery.</param>
/// <returns>The <see cref="IMvcCoreBuilder"/>.</returns>
public static IMvcCoreBuilder AddControllersAsServices(
[NotNull] this IMvcCoreBuilder builder,
[NotNull] IEnumerable<Type> controllerTypes)
{
ControllersAsServices.AddControllersAsServices(builder.Services, controllerTypes);
return builder;
}
/// <summary>
/// Registers controller types from the specified <paramref name="assemblies"/> as services and as a source
/// for controller discovery.
/// </summary>
/// <param name="builder">The <see cref="IMvcCoreBuilder"/>.</param>
/// <param name="controllerAssemblies">Assemblies to scan.</param>
/// <returns>The <see cref="IMvcCoreBuilder"/>.</returns>
public static IMvcCoreBuilder AddControllersAsServices(
[NotNull] this IMvcCoreBuilder builder,
[NotNull] IEnumerable<Assembly> controllerAssemblies)
{
ControllersAsServices.AddControllersAsServices(builder.Services, controllerAssemblies);
return builder;
}
}
}

View File

@ -21,38 +21,25 @@ namespace Microsoft.Framework.DependencyInjection
{
public static class MvcCoreServiceCollectionExtensions
{
public static IMvcBuilder AddMvcCore([NotNull] this IServiceCollection services)
public static IMvcCoreBuilder AddMvcCore([NotNull] this IServiceCollection services)
{
return AddMvcCore(services, setupAction: null);
}
public static IMvcCoreBuilder AddMvcCore(
[NotNull] this IServiceCollection services,
Action<MvcOptions> setupAction)
{
ConfigureDefaultServices(services);
AddMvcCoreServices(services);
return new MvcBuilder() { Services = services, };
}
if (setupAction != null)
{
services.Configure(setupAction);
}
public static IMvcBuilder AddMvcCore(
[NotNull] this IServiceCollection services,
[NotNull] Action<MvcOptions> setupAction)
{
ConfigureDefaultServices(services);
AddMvcCoreServices(services);
services.Configure(setupAction);
return new MvcBuilder() { Services = services, };
}
/// <summary>
/// Configures a set of <see cref="MvcOptions"/> for the application.
/// </summary>
/// <param name="services">The services available in the application.</param>
/// <param name="setupAction">The <see cref="MvcOptions"/> which need to be configured.</param>
public static void ConfigureMvc(
[NotNull] this IServiceCollection services,
[NotNull] Action<MvcOptions> setupAction)
{
services.Configure(setupAction);
return new MvcCoreBuilder(services);
}
// To enable unit testing
@ -147,10 +134,5 @@ namespace Microsoft.Framework.DependencyInjection
services.AddRouting();
services.AddNotifier();
}
private class MvcBuilder : IMvcBuilder
{
public IServiceCollection Services { get; set; }
}
}
}

View File

@ -35,6 +35,7 @@ namespace Microsoft.AspNet.Mvc
/// </summary>
public IList<TypeInfo> ControllerTypes { get; }
/// <inheritdoc />
IEnumerable<TypeInfo> IControllerTypeProvider.ControllerTypes => ControllerTypes;
}
}

View File

@ -0,0 +1,42 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Extensions;
namespace Microsoft.AspNet.Mvc.Internal
{
public static class ControllersAsServices
{
public static void AddControllersAsServices(IServiceCollection services, IEnumerable<Type> types)
{
var controllerTypeProvider = new FixedSetControllerTypeProvider();
foreach (var type in types)
{
services.TryAddTransient(type, type);
controllerTypeProvider.ControllerTypes.Add(type.GetTypeInfo());
}
services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
services.Replace(ServiceDescriptor.Instance<IControllerTypeProvider>(controllerTypeProvider));
}
public static void AddControllersAsServices(IServiceCollection services, IEnumerable<Assembly> assemblies)
{
var assemblyProvider = new FixedSetAssemblyProvider();
foreach (var assembly in assemblies)
{
assemblyProvider.CandidateAssemblies.Add(assembly);
}
var controllerTypeProvider = new DefaultControllerTypeProvider(assemblyProvider);
var controllerTypes = controllerTypeProvider.ControllerTypes;
AddControllersAsServices(services, controllerTypes.Select(type => type.AsType()));
}
}
}

View File

@ -0,0 +1,18 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.Internal
{
public class MvcBuilder : IMvcBuilder
{
public MvcBuilder([NotNull] IServiceCollection services)
{
Services = services;
}
public IServiceCollection Services { get; }
}
}

View File

@ -0,0 +1,18 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.Internal
{
public class MvcCoreBuilder : IMvcCoreBuilder
{
public MvcCoreBuilder([NotNull] IServiceCollection services)
{
Services = services;
}
public IServiceCollection Services { get; }
}
}

View File

@ -10,16 +10,16 @@ using Microsoft.Framework.Internal;
namespace Microsoft.Framework.DependencyInjection
{
public static class MvcCorsMvcBuilderExtensions
public static class MvcCorsMvcCoreBuilderExtensions
{
public static IMvcBuilder AddCors([NotNull] this IMvcBuilder builder)
public static IMvcCoreBuilder AddCors([NotNull] this IMvcCoreBuilder builder)
{
AddCorsServices(builder.Services);
return builder;
}
public static IMvcBuilder AddCors(
[NotNull] this IMvcBuilder builder,
public static IMvcCoreBuilder AddCors(
[NotNull] this IMvcCoreBuilder builder,
[NotNull] Action<CorsOptions> setupAction)
{
AddCorsServices(builder.Services);
@ -32,8 +32,8 @@ namespace Microsoft.Framework.DependencyInjection
return builder;
}
public static IMvcBuilder ConfigureCors(
[NotNull] this IMvcBuilder builder,
public static IMvcCoreBuilder ConfigureCors(
[NotNull] this IMvcCoreBuilder builder,
[NotNull] Action<CorsOptions> setupAction)
{
builder.Services.Configure(setupAction);

View File

@ -8,9 +8,9 @@ using Microsoft.Framework.OptionsModel;
namespace Microsoft.Framework.DependencyInjection
{
public static class MvcDataAnnotationsMvcBuilderExtensions
public static class MvcDataAnnotationsMvcCoreBuilderExtensions
{
public static IMvcBuilder AddDataAnnotations([NotNull] this IMvcBuilder builder)
public static IMvcCoreBuilder AddDataAnnotations([NotNull] this IMvcCoreBuilder builder)
{
AddDataAnnotationsServices(builder.Services);
return builder;

View File

@ -3,48 +3,26 @@
using System;
using Microsoft.AspNet.Mvc;
using Microsoft.Framework.DependencyInjection.Extensions;
using Microsoft.Framework.Internal;
using Microsoft.Framework.OptionsModel;
using Newtonsoft.Json;
namespace Microsoft.Framework.DependencyInjection
{
/// <summary>
/// Extensions methods for configuring MVC via an <see cref="IMvcBuilder"/>.
/// </summary>
public static class MvcJsonMvcBuilderExtensions
{
public static IMvcBuilder AddJsonFormatters([NotNull] this IMvcBuilder builder)
{
AddJsonFormatterServices(builder.Services);
return builder;
}
public static IMvcBuilder AddJsonFormatters(
[NotNull] this IMvcBuilder builder,
[NotNull] Action<JsonSerializerSettings> setupAction)
{
AddJsonFormatterServices(builder.Services);
if (setupAction != null)
{
builder.Services.Configure<MvcJsonOptions>((options) => setupAction(options.SerializerSettings));
}
return builder;
}
public static IMvcBuilder ConfigureJson(
/// <summary>
/// Adds configuration of <see cref="MvcJsonOptions"/> for the application.
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <param name="setupAction">The <see cref="MvcJsonOptions"/> which need to be configured.</param>
public static IMvcBuilder AddJsonOptions(
[NotNull] this IMvcBuilder builder,
[NotNull] Action<MvcJsonOptions> setupAction)
{
builder.Services.Configure(setupAction);
return builder;
}
// Internal for testing.
internal static void AddJsonFormatterServices(IServiceCollection services)
{
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcJsonMvcOptionsSetup>());
}
}
}

View File

@ -0,0 +1,42 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Mvc;
using Microsoft.Framework.DependencyInjection.Extensions;
using Microsoft.Framework.Internal;
using Microsoft.Framework.OptionsModel;
using Newtonsoft.Json;
namespace Microsoft.Framework.DependencyInjection
{
public static class MvcJsonMvcCoreBuilderExtensions
{
public static IMvcCoreBuilder AddJsonFormatters([NotNull] this IMvcCoreBuilder builder)
{
AddJsonFormatterServices(builder.Services);
return builder;
}
public static IMvcCoreBuilder AddJsonFormatters(
[NotNull] this IMvcCoreBuilder builder,
[NotNull] Action<JsonSerializerSettings> setupAction)
{
AddJsonFormatterServices(builder.Services);
if (setupAction != null)
{
builder.Services.Configure<MvcJsonOptions>((options) => setupAction(options.SerializerSettings));
}
return builder;
}
// Internal for testing.
internal static void AddJsonFormatterServices(IServiceCollection services)
{
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcJsonMvcOptionsSetup>());
}
}
}

View File

@ -0,0 +1,52 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Mvc;
using Microsoft.Framework.DependencyInjection.Extensions;
using Microsoft.Framework.Internal;
using Microsoft.Framework.OptionsModel;
namespace Microsoft.Framework.DependencyInjection
{
/// <summary>
/// Extension methods for adding XML formatters to MVC.
/// </summary>
public static class MvcXmlMvcCoreBuilderExtensions
{
/// <summary>
/// Adds the XML DataContractSerializer formatters to MVC.
/// </summary>
/// <param name="builder">The <see cref="IMvcCoreBuilder"/>.</param>
/// <returns>The <see cref="IMvcCoreBuilder"/>.</returns>
public static IMvcCoreBuilder AddXmlDataContractSerializerFormatters([NotNull] this IMvcCoreBuilder builder)
{
AddXmlDataContractSerializerFormatterServices(builder.Services);
return builder;
}
/// <summary>
/// Adds the XML Serializer formatters to MVC.
/// </summary>
/// <param name="builder">The <see cref="IMvcCoreBuilder"/>.</param>
/// <returns>The <see cref="IMvcCoreBuilder"/>.</returns>
public static IMvcCoreBuilder AddXmlSerializerFormatters([NotNull] this IMvcCoreBuilder builder)
{
AddXmlSerializerFormatterServices(builder.Services);
return builder;
}
// Internal for testing.
internal static void AddXmlDataContractSerializerFormatterServices(IServiceCollection services)
{
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcXmlDataContractSerializerMvcOptionsSetup>());
}
// Internal for testing.
internal static void AddXmlSerializerFormatterServices(IServiceCollection services)
{
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcXmlSerializerMvcOptionsSetup>());
}
}
}

View File

@ -1,21 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc
{
public static class MvcOptionsExtensions
{
/// <summary>
/// Adds <see cref="Microsoft.AspNet.Mvc.Formatters.Xml.XmlDataContractSerializerInputFormatter"/> and
/// <see cref="Microsoft.AspNet.Mvc.Formatters.Xml.XmlDataContractSerializerOutputFormatter"/> to the
/// input and output formatter collections respectively.
/// </summary>
/// <param name="options">The MvcOptions</param>
public static void AddXmlDataContractSerializerFormatter([NotNull] this MvcOptions options)
{
MvcXmlDataContractSerializerMvcOptionsSetup.ConfigureMvc(options);
}
}
}

View File

@ -1,8 +1,14 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Localization;
using Microsoft.AspNet.Mvc.Localization.Internal;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.Framework.DependencyInjection.Extensions;
using Microsoft.Framework.Internal;
using Microsoft.Framework.WebEncoders;
namespace Microsoft.Framework.DependencyInjection
{
@ -16,14 +22,9 @@ namespace Microsoft.Framework.DependencyInjection
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
/// <remarks>
/// Adding localization also adds support for views via
/// <see cref="MvcViewFeaturesMvcBuilderExtensions.AddViews(IMvcBuilder)"/> and the Razor view engine
/// via <see cref="MvcRazorMvcBuilderExtensions.AddRazorViewEngine(IMvcBuilder)"/>.
/// </remarks>
public static IMvcBuilder AddLocalization([NotNull] this IMvcBuilder builder)
public static IMvcBuilder AddViewLocalization([NotNull] this IMvcBuilder builder)
{
return AddLocalization(builder, LanguageViewLocationExpanderFormat.Suffix);
return AddViewLocalization(builder, LanguageViewLocationExpanderFormat.Suffix);
}
/// <summary>
@ -32,20 +33,11 @@ namespace Microsoft.Framework.DependencyInjection
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <param name="format">The view format for localized views.</param>
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
/// <remarks>
/// Adding localization also adds support for views via
/// <see cref="MvcViewFeaturesMvcBuilderExtensions.AddViews(IMvcBuilder)"/> and the Razor view engine
/// via <see cref="MvcRazorMvcBuilderExtensions.AddRazorViewEngine(IMvcBuilder)"/>.
/// </remarks>
public static IMvcBuilder AddLocalization(
public static IMvcBuilder AddViewLocalization(
[NotNull] this IMvcBuilder builder,
LanguageViewLocationExpanderFormat format)
{
builder.AddViews();
builder.AddRazorViewEngine();
MvcLocalizationServiceCollectionExtensions.AddMvcLocalization(builder.Services, format);
MvcLocalizationServices.AddLocalizationServices(builder.Services, format);
return builder;
}
}

View File

@ -0,0 +1,53 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Mvc.Localization.Internal;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.Framework.Internal;
namespace Microsoft.Framework.DependencyInjection
{
/// <summary>
/// Extension methods for configuring MVC view localization.
/// </summary>
public static class MvcLocalizationMvcCoreBuilderExtensions
{
/// <summary>
/// Adds MVC localization to the application.
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
/// <remarks>
/// Adding localization also adds support for views via
/// <see cref="MvcViewFeaturesMvcCoreBuilderExtensions.AddViews(IMvcCoreBuilder)"/> and the Razor view engine
/// via <see cref="MvcRazorMvcCoreBuilderExtensions.AddRazorViewEngine(IMvcCoreBuilder)"/>.
/// </remarks>
public static IMvcCoreBuilder AddViewLocalization([NotNull] this IMvcCoreBuilder builder)
{
return AddViewLocalization(builder, LanguageViewLocationExpanderFormat.Suffix);
}
/// <summary>
/// Adds MVC localization to the application.
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <param name="format">The view format for localized views.</param>
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
/// <remarks>
/// Adding localization also adds support for views via
/// <see cref="MvcViewFeaturesMvcCoreBuilderExtensions.AddViews(IMvcCoreBuilder)"/> and the Razor view engine
/// via <see cref="MvcRazorMvcCoreBuilderExtensions.AddRazorViewEngine(IMvcCoreBuilder)"/>.
/// </remarks>
public static IMvcCoreBuilder AddViewLocalization(
[NotNull] this IMvcCoreBuilder builder,
LanguageViewLocationExpanderFormat format)
{
builder.AddViews();
builder.AddRazorViewEngine();
MvcLocalizationServices.AddLocalizationServices(builder.Services, format);
return builder;
}
}
}

View File

@ -1,56 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Localization;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.Framework.DependencyInjection.Extensions;
using Microsoft.Framework.Internal;
using Microsoft.Framework.WebEncoders;
namespace Microsoft.Framework.DependencyInjection
{
/// <summary>
/// Extension methods for configuring MVC view localization.
/// </summary>
public static class MvcLocalizationServiceCollectionExtensions
{
/// <summary>
/// Adds MVC localization to the application.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
/// <returns>The <see cref="IServiceCollection"/>.</returns>
public static IServiceCollection AddMvcLocalization([NotNull] this IServiceCollection services)
{
return AddMvcLocalization(services, LanguageViewLocationExpanderFormat.Suffix);
}
/// <summary>
/// Adds MVC localization to the application.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
/// <param name="format">The view format for localized views.</param>
/// <returns>The <see cref="IServiceCollection"/>.</returns>
public static IServiceCollection AddMvcLocalization(
[NotNull] this IServiceCollection services,
LanguageViewLocationExpanderFormat format)
{
services.Configure<RazorViewEngineOptions>(
options =>
{
options.ViewLocationExpanders.Add(new LanguageViewLocationExpander(format));
},
DefaultOrder.DefaultFrameworkSortOrder);
services.TryAdd(ServiceDescriptor.Singleton<IHtmlLocalizerFactory, HtmlLocalizerFactory>());
services.TryAdd(ServiceDescriptor.Transient(typeof(IHtmlLocalizer<>), typeof(HtmlLocalizer<>)));
services.TryAdd(ServiceDescriptor.Transient<IViewLocalizer, ViewLocalizer>());
if (!services.Any(sd => sd.ServiceType == typeof(IHtmlEncoder)))
{
services.TryAdd(ServiceDescriptor.Instance<IHtmlEncoder>(HtmlEncoder.Default));
}
return services.AddLocalization();
}
}
}

View File

@ -0,0 +1,36 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Extensions;
using Microsoft.Framework.WebEncoders;
namespace Microsoft.AspNet.Mvc.Localization.Internal
{
public static class MvcLocalizationServices
{
public static void AddLocalizationServices(
IServiceCollection services,
LanguageViewLocationExpanderFormat format)
{
services.Configure<RazorViewEngineOptions>(
options =>
{
options.ViewLocationExpanders.Add(new LanguageViewLocationExpander(format));
},
DefaultOrder.DefaultFrameworkSortOrder);
services.TryAdd(ServiceDescriptor.Singleton<IHtmlLocalizerFactory, HtmlLocalizerFactory>());
services.TryAdd(ServiceDescriptor.Transient(typeof(IHtmlLocalizer<>), typeof(HtmlLocalizer<>)));
services.TryAdd(ServiceDescriptor.Transient<IViewLocalizer, ViewLocalizer>());
if (!services.Any(sd => sd.ServiceType == typeof(IHtmlEncoder)))
{
services.TryAdd(ServiceDescriptor.Instance<IHtmlEncoder>(HtmlEncoder.Default));
}
services.AddLocalization();
}
}
}

View File

@ -1,71 +1,29 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.AspNet.Mvc.Razor.Compilation;
using Microsoft.AspNet.Mvc.Razor.Directives;
using Microsoft.AspNet.Mvc.Razor.Precompilation;
using Microsoft.Framework.Caching.Memory;
using Microsoft.AspNet.Mvc.Razor.Internal;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.Framework.DependencyInjection.Extensions;
using Microsoft.Framework.Internal;
using Microsoft.Framework.OptionsModel;
namespace Microsoft.Framework.DependencyInjection
{
/// <summary>
/// Extensions methods for configuring MVC via an <see cref="IMvcBuilder"/>.
/// </summary>
public static class MvcRazorMvcBuilderExtensions
{
private static readonly Type RazorFileInfoCollectionType = typeof(RazorFileInfoCollection);
public static IMvcBuilder AddRazorViewEngine([NotNull] this IMvcBuilder builder)
{
builder.AddViews();
AddRazorViewEngineServices(builder.Services);
return builder;
}
public static IMvcBuilder AddRazorViewEngine(
[NotNull] this IMvcBuilder builder,
[NotNull] Action<RazorViewEngineOptions> setupAction)
{
builder.AddViews();
AddRazorViewEngineServices(builder.Services);
if (setupAction != null)
{
builder.Services.Configure(setupAction);
}
return builder;
}
public static IMvcBuilder AddPrecompiledRazorViews(
[NotNull] this IMvcBuilder builder,
[NotNull] params Assembly[] assemblies)
{
AddRazorViewEngine(builder);
var razorFileInfos = GetFileInfoCollections(assemblies);
builder.Services.TryAddEnumerable(ServiceDescriptor.Instance(razorFileInfos));
return builder;
}
public static IServiceCollection AddPrecompiledRazorViews(
[NotNull] this IServiceCollection collection,
[NotNull] params Assembly[] assemblies)
{
var razorFileInfos = GetFileInfoCollections(assemblies);
collection.TryAddEnumerable(ServiceDescriptor.Instance(razorFileInfos));
return collection;
}
public static IMvcBuilder ConfigureRazorViewEngine(
/// <summary>
/// Configures a set of <see cref="RazorViewEngineOptions"/> for the application.
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <param name="setupAction">An action to configure the <see cref="RazorViewEngineOptions"/>.</param>
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
public static IMvcBuilder AddRazorOptions(
[NotNull] this IMvcBuilder builder,
[NotNull] Action<RazorViewEngineOptions> setupAction)
{
@ -73,64 +31,36 @@ namespace Microsoft.Framework.DependencyInjection
return builder;
}
// Internal for testing.
internal static void AddRazorViewEngineServices(IServiceCollection services)
/// <summary>
/// Adds an initialization callback for a given <typeparamref name="TTagHelper"/>.
/// </summary>
/// <remarks>
/// The callback will be invoked on any <typeparamref name="TTagHelper"/> instance before the
/// <see cref="ITagHelper.ProcessAsync(TagHelperContext, TagHelperOutput)"/> method is called.
/// </remarks>
/// <typeparam name="TTagHelper">The type of <see cref="ITagHelper"/> being initialized.</typeparam>
/// <param name="builder">The <see cref="IMvcBuilder"/> instance this method extends.</param>
/// <param name="initialize">An action to initialize the <typeparamref name="TTagHelper"/>.</param>
/// <returns>The <see cref="IMvcBuilder"/> instance this method extends.</returns>
public static IMvcBuilder InitializeTagHelper<TTagHelper>(
[NotNull] this IMvcBuilder builder,
[NotNull] Action<TTagHelper, ViewContext> initialize)
where TTagHelper : ITagHelper
{
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcViewOptions>, MvcRazorMvcViewOptionsSetup>());
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<RazorViewEngineOptions>, RazorViewEngineOptionsSetup>());
var initializer = new TagHelperInitializer<TTagHelper>(initialize);
services.TryAddSingleton<IRazorViewEngine, RazorViewEngine>();
builder.Services.AddInstance(typeof(ITagHelperInitializer<TTagHelper>), initializer);
// Caches view locations that are valid for the lifetime of the application.
services.TryAddSingleton<IViewLocationCache, DefaultViewLocationCache>();
services.TryAdd(ServiceDescriptor.Singleton<IChunkTreeCache>(serviceProvider =>
{
var cachedFileProvider = serviceProvider.GetRequiredService<IOptions<RazorViewEngineOptions>>();
return new DefaultChunkTreeCache(cachedFileProvider.Options.FileProvider);
}));
// The host is designed to be discarded after consumption and is very inexpensive to initialize.
services.TryAddTransient<IMvcRazorHost, MvcRazorHost>();
// Caches compilation artifacts across the lifetime of the application.
services.TryAddSingleton<ICompilerCache, CompilerCache>();
// This caches compilation related details that are valid across the lifetime of the application
// and is required to be a singleton.
services.TryAddSingleton<ICompilationService, RoslynCompilationService>();
// Both the compiler cache and roslyn compilation service hold on the compilation related
// caches. RazorCompilation service is just an adapter service, and it is transient to ensure
// the IMvcRazorHost dependency does not maintain state.
services.TryAddTransient<IRazorCompilationService, RazorCompilationService>();
// The ViewStartProvider needs to be able to consume scoped instances of IRazorPageFactory
services.TryAddScoped<IViewStartProvider, ViewStartProvider>();
services.TryAddTransient<IRazorViewFactory, RazorViewFactory>();
services.TryAddSingleton<IRazorPageActivator, RazorPageActivator>();
// Virtual path view factory needs to stay scoped so views can get get scoped services.
services.TryAddScoped<IRazorPageFactory, VirtualPathRazorPageFactory>();
// Only want one ITagHelperActivator so it can cache Type activation information. Types won't conflict.
services.TryAddSingleton<ITagHelperActivator, DefaultTagHelperActivator>();
// Consumed by the Cache tag helper to cache results across the lifetime of the application.
services.TryAddSingleton<IMemoryCache, MemoryCache>();
return builder;
}
public static IMvcBuilder AddPrecompiledRazorViews(
[NotNull] this IMvcBuilder builder,
[NotNull] params Assembly[] assemblies)
{
var razorFileInfos = RazorFileInfoCollections.GetFileInfoCollections(assemblies);
builder.Services.TryAddEnumerable(ServiceDescriptor.Instance(razorFileInfos));
return builder;
}
private static IEnumerable<RazorFileInfoCollection> GetFileInfoCollections(IEnumerable<Assembly> assemblies) =>
assemblies
.SelectMany(assembly => assembly.ExportedTypes)
.Where(IsValidRazorFileInfoCollection)
.Select(Activator.CreateInstance)
.Cast<RazorFileInfoCollection>();
internal static bool IsValidRazorFileInfoCollection(Type type) =>
RazorFileInfoCollectionType.IsAssignableFrom(type) &&
!type.GetTypeInfo().IsAbstract &&
!type.GetTypeInfo().ContainsGenericParameters;
}
}
}

View File

@ -0,0 +1,126 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Reflection;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.AspNet.Mvc.Razor.Compilation;
using Microsoft.AspNet.Mvc.Razor.Directives;
using Microsoft.AspNet.Mvc.Razor.Internal;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.Framework.Caching.Memory;
using Microsoft.Framework.DependencyInjection.Extensions;
using Microsoft.Framework.Internal;
using Microsoft.Framework.OptionsModel;
namespace Microsoft.Framework.DependencyInjection
{
public static class MvcRazorMvcCoreBuilderExtensions
{
public static IMvcCoreBuilder AddRazorViewEngine([NotNull] this IMvcCoreBuilder builder)
{
builder.AddViews();
AddRazorViewEngineServices(builder.Services);
return builder;
}
public static IMvcCoreBuilder AddRazorViewEngine(
[NotNull] this IMvcCoreBuilder builder,
[NotNull] Action<RazorViewEngineOptions> setupAction)
{
builder.AddViews();
AddRazorViewEngineServices(builder.Services);
if (setupAction != null)
{
builder.Services.Configure(setupAction);
}
return builder;
}
public static IMvcCoreBuilder AddPrecompiledRazorViews(
[NotNull] this IMvcCoreBuilder builder,
[NotNull] params Assembly[] assemblies)
{
AddRazorViewEngine(builder);
var razorFileInfos = RazorFileInfoCollections.GetFileInfoCollections(assemblies);
builder.Services.TryAddEnumerable(ServiceDescriptor.Instance(razorFileInfos));
return builder;
}
/// <summary>
/// Adds an initialization callback for a given <typeparamref name="TTagHelper"/>.
/// </summary>
/// <remarks>
/// The callback will be invoked on any <typeparamref name="TTagHelper"/> instance before the
/// <see cref="ITagHelper.ProcessAsync(TagHelperContext, TagHelperOutput)"/> method is called.
/// </remarks>
/// <typeparam name="TTagHelper">The type of <see cref="ITagHelper"/> being initialized.</typeparam>
/// <param name="builder">The <see cref="IMvcCoreBuilder"/> instance this method extends.</param>
/// <param name="initialize">An action to initialize the <typeparamref name="TTagHelper"/>.</param>
/// <returns>The <see cref="IMvcCoreBuilder"/> instance this method extends.</returns>
public static IMvcCoreBuilder InitializeTagHelper<TTagHelper>(
[NotNull] this IMvcCoreBuilder builder,
[NotNull] Action<TTagHelper, ViewContext> initialize)
where TTagHelper : ITagHelper
{
var initializer = new TagHelperInitializer<TTagHelper>(initialize);
builder.Services.AddInstance(typeof(ITagHelperInitializer<TTagHelper>), initializer);
return builder;
}
// Internal for testing.
internal static void AddRazorViewEngineServices(IServiceCollection services)
{
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcViewOptions>, MvcRazorMvcViewOptionsSetup>());
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<RazorViewEngineOptions>, RazorViewEngineOptionsSetup>());
services.TryAddSingleton<IRazorViewEngine, RazorViewEngine>();
// Caches view locations that are valid for the lifetime of the application.
services.TryAddSingleton<IViewLocationCache, DefaultViewLocationCache>();
services.TryAdd(ServiceDescriptor.Singleton<IChunkTreeCache>(serviceProvider =>
{
var cachedFileProvider = serviceProvider.GetRequiredService<IOptions<RazorViewEngineOptions>>();
return new DefaultChunkTreeCache(cachedFileProvider.Options.FileProvider);
}));
// The host is designed to be discarded after consumption and is very inexpensive to initialize.
services.TryAddTransient<IMvcRazorHost, MvcRazorHost>();
// Caches compilation artifacts across the lifetime of the application.
services.TryAddSingleton<ICompilerCache, CompilerCache>();
// This caches compilation related details that are valid across the lifetime of the application
// and is required to be a singleton.
services.TryAddSingleton<ICompilationService, RoslynCompilationService>();
// Both the compiler cache and roslyn compilation service hold on the compilation related
// caches. RazorCompilation service is just an adapter service, and it is transient to ensure
// the IMvcRazorHost dependency does not maintain state.
services.TryAddTransient<IRazorCompilationService, RazorCompilationService>();
// The ViewStartProvider needs to be able to consume scoped instances of IRazorPageFactory
services.TryAddScoped<IViewStartProvider, ViewStartProvider>();
services.TryAddTransient<IRazorViewFactory, RazorViewFactory>();
services.TryAddSingleton<IRazorPageActivator, RazorPageActivator>();
// Virtual path view factory needs to stay scoped so views can get get scoped services.
services.TryAddScoped<IRazorPageFactory, VirtualPathRazorPageFactory>();
// Only want one ITagHelperActivator so it can cache Type activation information. Types won't conflict.
services.TryAddSingleton<ITagHelperActivator, DefaultTagHelperActivator>();
// Consumed by the Cache tag helper to cache results across the lifetime of the application.
services.TryAddSingleton<IMemoryCache, MemoryCache>();
}
}
}

View File

@ -0,0 +1,34 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Mvc.Razor.Precompilation;
namespace Microsoft.AspNet.Mvc.Razor.Internal
{
public static class RazorFileInfoCollections
{
private static readonly Type RazorFileInfoCollectionType = typeof(RazorFileInfoCollection);
public static IEnumerable<RazorFileInfoCollection> GetFileInfoCollections(IEnumerable<Assembly> assemblies)
{
return assemblies
.SelectMany(assembly => assembly.ExportedTypes)
.Where(IsValidRazorFileInfoCollection)
.Select(Activator.CreateInstance)
.Cast<RazorFileInfoCollection>();
}
public static bool IsValidRazorFileInfoCollection(Type type)
{
return
RazorFileInfoCollectionType.IsAssignableFrom(type) &&
!type.GetTypeInfo().IsAbstract &&
!type.GetTypeInfo().ContainsGenericParameters;
}
}
}

View File

@ -1,52 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.Framework.Internal;
namespace Microsoft.Framework.DependencyInjection
{
/// <summary>
/// Contains extension methods to <see cref="IServiceCollection"/>.
/// </summary>
public static class ServiceCollectionExtensions
{
/// <summary>
/// Configures a set of <see cref="RazorViewEngineOptions"/> for the application.
/// </summary>
/// <param name="services">The services available in the application.</param>
/// <param name="setupAction">An action to configure the <see cref="RazorViewEngineOptions"/>.</param>
public static void ConfigureRazorViewEngine(
[NotNull] this IServiceCollection services,
[NotNull] Action<RazorViewEngineOptions> setupAction)
{
services.Configure(setupAction);
}
/// <summary>
/// Adds an initialization callback for a given <typeparamref name="TTagHelper"/>.
/// </summary>
/// <remarks>
/// The callback will be invoked on any <typeparamref name="TTagHelper"/> instance before the
/// <see cref="ITagHelper.ProcessAsync(TagHelperContext, TagHelperOutput)"/> method is called.
/// </remarks>
/// <typeparam name="TTagHelper">The type of <see cref="ITagHelper"/> being initialized.</typeparam>
/// <param name="services">The <see cref="IServiceCollection"/> instance this method extends.</param>
/// <param name="initialize">An action to initialize the <typeparamref name="TTagHelper"/>.</param>
/// <returns>The <see cref="IServiceCollection"/> instance this method extends.</returns>
public static IServiceCollection InitializeTagHelper<TTagHelper>(
[NotNull] this IServiceCollection services,
[NotNull] Action<TTagHelper, ViewContext> initialize)
where TTagHelper : ITagHelper
{
var initializer = new TagHelperInitializer<TTagHelper>(initialize);
services.AddInstance(typeof(ITagHelperInitializer<TTagHelper>), initializer);
return services;
}
}
}

View File

@ -3,111 +3,26 @@
using System;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.ViewComponents;
using Microsoft.Framework.DependencyInjection.Extensions;
using Microsoft.Framework.Internal;
using Microsoft.Framework.OptionsModel;
namespace Microsoft.Framework.DependencyInjection
{
/// <summary>
/// Extensions methods for configuring MVC via an <see cref="IMvcBuilder"/>.
/// </summary>
public static class MvcViewFeaturesMvcBuilderExtensions
{
public static IMvcBuilder AddViews([NotNull] this IMvcBuilder builder)
{
builder.AddDataAnnotations();
AddViewServices(builder.Services);
return builder;
}
public static IMvcBuilder AddViews(
[NotNull] this IMvcBuilder builder,
[NotNull] Action<MvcViewOptions> setupAction)
{
builder.AddDataAnnotations();
AddViewServices(builder.Services);
if (setupAction != null)
{
builder.Services.Configure(setupAction);
}
return builder;
}
public static IMvcBuilder ConfigureViews(
/// <summary>
/// Adds configuration of <see cref="MvcViewOptions"/> for the application.
/// </summary>
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
/// <param name="setupAction">The <see cref="MvcViewOptions"/> which need to be configured.</param>
public static IMvcBuilder AddViewOptions(
[NotNull] this IMvcBuilder builder,
[NotNull] Action<MvcViewOptions> setupAction)
{
builder.Services.Configure(setupAction);
return builder;
}
// Internal for testing.
internal static void AddViewServices(IServiceCollection services)
{
services.AddDataProtection();
services.AddAntiforgery();
services.AddWebEncoders();
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcViewOptions>, MvcViewOptionsSetup>());
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, TempDataMvcOptionsSetup>());
//
// View Engine and related infrastructure
//
services.TryAddSingleton<ICompositeViewEngine, CompositeViewEngine>();
// Support for activating ViewDataDictionary
services.TryAddEnumerable(
ServiceDescriptor
.Transient<IControllerPropertyActivator, ViewDataDictionaryControllerPropertyActivator>());
//
// HTML Helper
//
services.TryAddTransient<IHtmlHelper, HtmlHelper>();
services.TryAddTransient(typeof(IHtmlHelper<>), typeof(HtmlHelper<>));
// DefaultHtmlGenerator is pretty much stateless but depends on IUrlHelper, which is scoped.
// Therefore it too is scoped.
services.TryAddScoped<IHtmlGenerator, DefaultHtmlGenerator>();
//
// JSON Helper
//
services.TryAddSingleton<IJsonHelper, JsonHelper>();
services.TryAdd(ServiceDescriptor.Singleton<JsonOutputFormatter>(serviceProvider =>
{
var options = serviceProvider.GetRequiredService<IOptions<MvcJsonOptions>>().Options;
return new JsonOutputFormatter(options.SerializerSettings);
}));
//
// View Components
//
// These do caching so they should stay singleton
services.TryAddSingleton<IViewComponentSelector, DefaultViewComponentSelector>();
services.TryAddSingleton<IViewComponentActivator, DefaultViewComponentActivator>();
services.TryAddSingleton<
IViewComponentDescriptorCollectionProvider,
DefaultViewComponentDescriptorCollectionProvider>();
services.TryAddTransient<IViewComponentDescriptorProvider, DefaultViewComponentDescriptorProvider>();
services.TryAddSingleton<IViewComponentInvokerFactory, DefaultViewComponentInvokerFactory>();
services.TryAddTransient<IViewComponentHelper, DefaultViewComponentHelper>();
//
// Temp Data
//
// Holds per-request data so it should be scoped
services.TryAddScoped<ITempDataDictionary, TempDataDictionary>();
services.TryAddScoped<SaveTempDataFilter>();
// This does caching so it should stay singleton
services.TryAddSingleton<ITempDataProvider, SessionStateTempDataProvider>();
}
}
}

View File

@ -0,0 +1,113 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.ViewComponents;
using Microsoft.Framework.DependencyInjection.Extensions;
using Microsoft.Framework.Internal;
using Microsoft.Framework.OptionsModel;
namespace Microsoft.Framework.DependencyInjection
{
public static class MvcViewFeaturesMvcCoreBuilderExtensions
{
public static IMvcCoreBuilder AddViews([NotNull] this IMvcCoreBuilder builder)
{
builder.AddDataAnnotations();
AddViewServices(builder.Services);
return builder;
}
public static IMvcCoreBuilder AddViews(
[NotNull] this IMvcCoreBuilder builder,
[NotNull] Action<MvcViewOptions> setupAction)
{
builder.AddDataAnnotations();
AddViewServices(builder.Services);
if (setupAction != null)
{
builder.Services.Configure(setupAction);
}
return builder;
}
public static IMvcCoreBuilder ConfigureViews(
[NotNull] this IMvcCoreBuilder builder,
[NotNull] Action<MvcViewOptions> setupAction)
{
builder.Services.Configure(setupAction);
return builder;
}
// Internal for testing.
internal static void AddViewServices(IServiceCollection services)
{
services.AddDataProtection();
services.AddAntiforgery();
services.AddWebEncoders();
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcViewOptions>, MvcViewOptionsSetup>());
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, TempDataMvcOptionsSetup>());
//
// View Engine and related infrastructure
//
services.TryAddSingleton<ICompositeViewEngine, CompositeViewEngine>();
// Support for activating ViewDataDictionary
services.TryAddEnumerable(
ServiceDescriptor
.Transient<IControllerPropertyActivator, ViewDataDictionaryControllerPropertyActivator>());
//
// HTML Helper
//
services.TryAddTransient<IHtmlHelper, HtmlHelper>();
services.TryAddTransient(typeof(IHtmlHelper<>), typeof(HtmlHelper<>));
// DefaultHtmlGenerator is pretty much stateless but depends on IUrlHelper, which is scoped.
// Therefore it too is scoped.
services.TryAddScoped<IHtmlGenerator, DefaultHtmlGenerator>();
//
// JSON Helper
//
services.TryAddSingleton<IJsonHelper, JsonHelper>();
services.TryAdd(ServiceDescriptor.Singleton<JsonOutputFormatter>(serviceProvider =>
{
var options = serviceProvider.GetRequiredService<IOptions<MvcJsonOptions>>().Options;
return new JsonOutputFormatter(options.SerializerSettings);
}));
//
// View Components
//
// These do caching so they should stay singleton
services.TryAddSingleton<IViewComponentSelector, DefaultViewComponentSelector>();
services.TryAddSingleton<IViewComponentActivator, DefaultViewComponentActivator>();
services.TryAddSingleton<
IViewComponentDescriptorCollectionProvider,
DefaultViewComponentDescriptorCollectionProvider>();
services.TryAddTransient<IViewComponentDescriptorProvider, DefaultViewComponentDescriptorProvider>();
services.TryAddSingleton<IViewComponentInvokerFactory, DefaultViewComponentInvokerFactory>();
services.TryAddTransient<IViewComponentHelper, DefaultViewComponentHelper>();
//
// Temp Data
//
// Holds per-request data so it should be scoped
services.TryAddScoped<ITempDataDictionary, TempDataDictionary>();
services.TryAddScoped<SaveTempDataFilter>();
// This does caching so it should stay singleton
services.TryAddSingleton<ITempDataProvider, SessionStateTempDataProvider>();
}
}
}

View File

@ -9,20 +9,20 @@ using Microsoft.Framework.OptionsModel;
namespace Microsoft.Framework.DependencyInjection
{
public static class WebApiCompatShimServiceCollectionExtensions
public static class WebApiCompatShimMvcBuilderExtensions
{
public static IServiceCollection AddWebApiConventions(this IServiceCollection services)
public static IMvcBuilder AddWebApiConventions(this IMvcBuilder builder)
{
services.TryAddEnumerable(
builder.Services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, WebApiCompatShimOptionsSetup>());
services.TryAddEnumerable(
builder.Services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<WebApiCompatShimOptions>, WebApiCompatShimOptionsSetup>());
// The constructors on DefaultContentNegotiator aren't DI friendly, so just
// new it up.
services.TryAdd(ServiceDescriptor.Instance<IContentNegotiator>(new DefaultContentNegotiator()));
builder.Services.TryAdd(ServiceDescriptor.Instance<IContentNegotiator>(new DefaultContentNegotiator()));
return services;
return builder;
}
}
}

View File

@ -2,18 +2,20 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Mvc;
using Microsoft.Framework.DependencyInjection.Extensions;
using Microsoft.AspNet.Mvc.Internal;
using Microsoft.Framework.Internal;
namespace Microsoft.Framework.DependencyInjection
{
public static class MvcServiceCollectionExtensions
{
public static IServiceCollection AddMvc([NotNull] this IServiceCollection services)
public static IMvcBuilder AddMvc([NotNull] this IServiceCollection services)
{
return AddMvc(services, setupAction: null);
}
public static IMvcBuilder AddMvc([NotNull] this IServiceCollection services, Action<MvcOptions> setupAction)
{
var builder = services.AddMvcCore();
@ -26,79 +28,12 @@ namespace Microsoft.Framework.DependencyInjection
builder.AddViews();
builder.AddRazorViewEngine();
return services;
}
/// <summary>
/// Configures a set of <see cref="MvcViewOptions"/> for the application.
/// </summary>
/// <param name="services">The services available in the application.</param>
/// <param name="setupAction">The <see cref="MvcViewOptions"/> which need to be configured.</param>
public static void ConfigureMvcViews(
[NotNull] this IServiceCollection services,
[NotNull] Action<MvcViewOptions> setupAction)
{
services.Configure(setupAction);
}
/// <summary>
/// Configures a set of <see cref="MvcJsonOptions"/> for the application.
/// </summary>
/// <param name="services">The services available in the application.</param>
/// <param name="setupAction">The <see cref="MvcJsonOptions"/> which need to be configured.</param>
public static void ConfigureMvcJson(
[NotNull] this IServiceCollection services,
[NotNull] Action<MvcJsonOptions> setupAction)
{
services.Configure(setupAction);
}
/// <summary>
/// Register the specified <paramref name="controllerTypes"/> as services and as a source for controller
/// discovery.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
/// <param name="controllerTypes">A sequence of controller <see cref="Type"/>s to register in the
/// <paramref name="services"/> and used for controller discovery.</param>
/// <returns>The <see cref="IServiceCollection"/>.</returns>
public static IServiceCollection WithControllersAsServices(
[NotNull] this IServiceCollection services,
[NotNull] IEnumerable<Type> controllerTypes)
{
var controllerTypeProvider = new FixedSetControllerTypeProvider();
foreach (var type in controllerTypes)
if (setupAction != null)
{
services.TryAddTransient(type, type);
controllerTypeProvider.ControllerTypes.Add(type.GetTypeInfo());
builder.Services.Configure(setupAction);
}
services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
services.Replace(ServiceDescriptor.Instance<IControllerTypeProvider>(controllerTypeProvider));
return services;
}
/// <summary>
/// Registers controller types from the specified <paramref name="assemblies"/> as services and as a source
/// for controller discovery.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
/// <param name="controllerAssemblies">Assemblies to scan.</param>
/// <returns>The <see cref="IServiceCollection"/>.</returns>
public static IServiceCollection WithControllersAsServices(
[NotNull] this IServiceCollection services,
[NotNull] IEnumerable<Assembly> controllerAssemblies)
{
var assemblyProvider = new FixedSetAssemblyProvider();
foreach (var assembly in controllerAssemblies)
{
assemblyProvider.CandidateAssemblies.Add(assembly);
}
var controllerTypeProvider = new DefaultControllerTypeProvider(assemblyProvider);
var controllerTypes = controllerTypeProvider.ControllerTypes;
return WithControllersAsServices(services, controllerTypes.Select(type => type.AsType()));
return new MvcBuilder(services);
}
}
}

View File

@ -0,0 +1,71 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Mvc.MvcServiceCollectionExtensionsTestControllers;
using Microsoft.Framework.DependencyInjection;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc
{
public class MvcBuilderExtensionsTest
{
[Fact]
public void WithControllersAsServices_AddsTypesToControllerTypeProviderAndServiceCollection()
{
// Arrange
var builder = new Mock<IMvcBuilder>();
var collection = new ServiceCollection();
builder.SetupGet(b => b.Services).Returns(collection);
var controllerTypes = new[]
{
typeof(ControllerTypeA).GetTypeInfo(),
typeof(TypeBController).GetTypeInfo(),
};
// Act
builder.Object.AddControllersAsServices(controllerTypes);
// Assert
var services = collection.ToList();
Assert.Equal(4, services.Count);
Assert.Equal(typeof(ControllerTypeA), services[0].ServiceType);
Assert.Equal(typeof(ControllerTypeA), services[0].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[0].Lifetime);
Assert.Equal(typeof(TypeBController), services[1].ServiceType);
Assert.Equal(typeof(TypeBController), services[1].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[1].Lifetime);
Assert.Equal(typeof(IControllerActivator), services[2].ServiceType);
Assert.Equal(typeof(ServiceBasedControllerActivator), services[2].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[2].Lifetime);
Assert.Equal(typeof(IControllerTypeProvider), services[3].ServiceType);
var typeProvider = Assert.IsType<FixedSetControllerTypeProvider>(services[3].ImplementationInstance);
Assert.Equal(controllerTypes, typeProvider.ControllerTypes.OrderBy(c => c.Name));
Assert.Equal(ServiceLifetime.Singleton, services[3].Lifetime);
}
}
}
// These controllers are used to test the UseControllersAsServices implementation
// which REQUIRES that they be public top-level classes. To avoid having to stub out the
// implementation of this class to test it, they are just top level classes. Don't reuse
// these outside this test - find a better way or use nested classes to keep the tests
// independent.
namespace Microsoft.AspNet.Mvc.MvcServiceCollectionExtensionsTestControllers
{
public class ControllerTypeA : Controller
{
}
public class TypeBController
{
}
}

View File

@ -11,6 +11,7 @@ using System.Reflection;
using System.Threading.Tasks;
using HtmlGenerationWebSite;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Mvc.Internal;
using Microsoft.AspNet.Mvc.TagHelpers;
using Microsoft.AspNet.Testing;
using Microsoft.Framework.DependencyInjection;
@ -502,7 +503,8 @@ Products: Laptops (3)";
{
// Arrange
var newServices = new ServiceCollection();
newServices.InitializeTagHelper<FormTagHelper>((helper, _) => helper.Antiforgery = optionsAntiforgery);
var builder = new MvcCoreBuilder(newServices);
builder.InitializeTagHelper<FormTagHelper>((helper, _) => helper.Antiforgery = optionsAntiforgery);
var server = TestHelper.CreateServer(_app, SiteName,
services =>
{

View File

@ -5,8 +5,8 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.AspNet.Mvc.Localization;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.Extensions;
using Microsoft.Framework.Localization;
using Microsoft.Framework.OptionsModel;
@ -14,18 +14,20 @@ using Microsoft.Framework.WebEncoders;
using Microsoft.Framework.WebEncoders.Testing;
using Xunit;
namespace Microsoft.Framework.DependencyInjection
namespace Microsoft.AspNet.Mvc.Localization.Internal
{
public class MvcLocalizationServiceCollectionExtensionsTest
public class MvcLocalizationServicesTest
{
[Fact]
public void AddMvcLocalization_AddsNeededServices()
public void AddLocalizationServices_AddsNeededServices()
{
// Arrange
var collection = new ServiceCollection();
// Act
MvcLocalizationServiceCollectionExtensions.AddMvcLocalization(collection);
MvcLocalizationServices.AddLocalizationServices(
collection,
LanguageViewLocationExpanderFormat.Suffix);
// Assert
var services = collection.ToList();
@ -59,7 +61,7 @@ namespace Microsoft.Framework.DependencyInjection
}
[Fact]
public void AddCustomLocalizers_BeforeMvcLocalization_AddsNeededServices()
public void AddCustomLocalizers_BeforeAddLocalizationServices_AddsNeededServices()
{
// Arrange
var collection = new ServiceCollection();
@ -70,7 +72,9 @@ namespace Microsoft.Framework.DependencyInjection
collection.Add(ServiceDescriptor.Transient(typeof(IViewLocalizer), typeof(TestViewLocalizer)));
collection.Add(ServiceDescriptor.Instance(typeof(IHtmlEncoder), typeof(CommonTestEncoder)));
MvcLocalizationServiceCollectionExtensions.AddMvcLocalization(collection);
MvcLocalizationServices.AddLocalizationServices(
collection,
LanguageViewLocationExpanderFormat.Suffix);
// Assert
var services = collection.ToList();
@ -94,7 +98,7 @@ namespace Microsoft.Framework.DependencyInjection
}
[Fact]
public void AddCustomLocalizers_AfterMvcLocalization_AddsNeededServices()
public void AddCustomLocalizers_AfterAddLocalizationServices_AddsNeededServices()
{
// Arrange
var collection = new ServiceCollection();
@ -105,7 +109,9 @@ namespace Microsoft.Framework.DependencyInjection
});
// Act
MvcLocalizationServiceCollectionExtensions.AddMvcLocalization(collection);
MvcLocalizationServices.AddLocalizationServices(
collection,
LanguageViewLocationExpanderFormat.Suffix);
collection.Add(ServiceDescriptor.Transient(typeof(IHtmlLocalizer<>), typeof(TestHtmlLocalizer<>)));
collection.Add(ServiceDescriptor.Transient(typeof(IHtmlLocalizer), typeof(TestViewLocalizer)));

View File

@ -5,6 +5,7 @@ using System;
using System.IO;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Internal;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
@ -24,7 +25,8 @@ namespace Microsoft.AspNet.Mvc.Razor
{
// Arrange
var services = new ServiceCollection();
services.InitializeTagHelper<TestTagHelper>((h, vc) =>
var builder = new MvcCoreBuilder(services);
builder.InitializeTagHelper<TestTagHelper>((h, vc) =>
{
h.Name = name;
h.Number = number;
@ -51,7 +53,8 @@ namespace Microsoft.AspNet.Mvc.Razor
{
// Arrange
var services = new ServiceCollection();
services.InitializeTagHelper<TestTagHelper>((h, _) => h.ViewContext = MakeViewContext(MakeHttpContext()));
var builder = new MvcCoreBuilder(services);
builder.InitializeTagHelper<TestTagHelper>((h, _) => h.ViewContext = MakeViewContext(MakeHttpContext()));
var httpContext = MakeHttpContext(services.BuildServiceProvider());
var viewContext = MakeViewContext(httpContext);
var activator = new DefaultTagHelperActivator();
@ -69,12 +72,13 @@ namespace Microsoft.AspNet.Mvc.Razor
{
// Arrange
var services = new ServiceCollection();
services.InitializeTagHelper<TestTagHelper>((h, vc) =>
var builder = new MvcCoreBuilder(services);
builder.InitializeTagHelper<TestTagHelper>((h, vc) =>
{
h.Name = "Test 1";
h.Number = 100;
});
services.InitializeTagHelper<TestTagHelper>((h, vc) =>
builder.InitializeTagHelper<TestTagHelper>((h, vc) =>
{
h.Name += ", Test 2";
h.Number += 100;
@ -97,12 +101,13 @@ namespace Microsoft.AspNet.Mvc.Razor
{
// Arrange
var services = new ServiceCollection();
services.InitializeTagHelper<TestTagHelper>((h, vc) =>
var builder = new MvcCoreBuilder(services);
builder.InitializeTagHelper<TestTagHelper>((h, vc) =>
{
h.Name = "Test 1";
h.Number = 100;
});
services.InitializeTagHelper<AnotherTestTagHelper>((h, vc) =>
builder.InitializeTagHelper<AnotherTestTagHelper>((h, vc) =>
{
h.Name = "Test 2";
h.Number = 102;

View File

@ -3,12 +3,13 @@
using System;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Razor.Internal;
using Microsoft.AspNet.Mvc.Razor.Precompilation;
using Xunit;
namespace Microsoft.Framework.DependencyInjection
{
public class MvcRazorMvcBuilderExtensionsTest
public class RazorFileInfoCollectionsTest
{
[Fact]
public void IsValidRazorFileInfoCollection_ReturnsFalse_IfTypeIsAbstract()
@ -17,7 +18,7 @@ namespace Microsoft.Framework.DependencyInjection
var type = typeof(AbstractRazorFileInfoCollection);
// Act
var result = MvcRazorMvcBuilderExtensions.IsValidRazorFileInfoCollection(type);
var result = RazorFileInfoCollections.IsValidRazorFileInfoCollection(type);
// Assert
Assert.False(result);
@ -30,7 +31,7 @@ namespace Microsoft.Framework.DependencyInjection
var type = typeof(GenericRazorFileInfoCollection<>);
// Act
var result = MvcRazorMvcBuilderExtensions.IsValidRazorFileInfoCollection(type);
var result = RazorFileInfoCollections.IsValidRazorFileInfoCollection(type);
// Assert
Assert.False(result);
@ -43,7 +44,7 @@ namespace Microsoft.Framework.DependencyInjection
var type = typeof(NonSubTypeRazorFileInfoCollection);
// Act
var result = MvcRazorMvcBuilderExtensions.IsValidRazorFileInfoCollection(type);
var result = RazorFileInfoCollections.IsValidRazorFileInfoCollection(type);
// Assert
Assert.False(result);
@ -55,7 +56,7 @@ namespace Microsoft.Framework.DependencyInjection
public void IsValidRazorFileInfoCollection_ReturnsTrue_IfTypeDerivesFromRazorFileInfoCollection(Type type)
{
// Act
var result = MvcRazorMvcBuilderExtensions.IsValidRazorFileInfoCollection(type);
var result = RazorFileInfoCollections.IsValidRazorFileInfoCollection(type);
// Assert
Assert.True(result);

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.Mvc.Internal;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel;
using Xunit;
@ -22,14 +23,15 @@ namespace Microsoft.AspNet.Mvc.Razor
}
[Fact]
public void ConfigureRazorViewEngine_ConfiguresOptionsProperly()
public void AddRazorOptions_ConfiguresOptionsProperly()
{
// Arrange
var services = new ServiceCollection().AddOptions();
var fileProvider = new TestFileProvider();
// Act
services.ConfigureRazorViewEngine(options =>
var builder = new MvcBuilder(services);
builder.AddRazorOptions(options =>
{
options.FileProvider = fileProvider;
});

View File

@ -5,6 +5,7 @@ using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Microsoft.AspNet.Mvc.Internal;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Microsoft.AspNet.Mvc.Razor;
@ -134,7 +135,11 @@ namespace Microsoft.AspNet.Mvc
public void Setup_SetsUpExcludeFromValidationDelegates()
{
// Arrange & Act
var options = GetOptions<MvcOptions>(_ => _.ConfigureMvc(o => o.AddXmlDataContractSerializerFormatter()));
var options = GetOptions<MvcOptions>(services =>
{
var builder = new MvcCoreBuilder(services);
builder.AddXmlDataContractSerializerFormatters();
});
// Assert
Assert.Equal(8, options.ValidationExcludeFilters.Count);

View File

@ -10,7 +10,6 @@ using Microsoft.AspNet.Mvc.ApiExplorer;
using Microsoft.AspNet.Mvc.ApplicationModels;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Filters;
using Microsoft.AspNet.Mvc.MvcServiceCollectionExtensionsTestControllers;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.DependencyInjection;
@ -23,71 +22,6 @@ namespace Microsoft.AspNet.Mvc
{
public class MvcServiceCollectionExtensionsTest
{
[Fact]
public void WithControllersAsServices_AddsTypesToControllerTypeProviderAndServiceCollection()
{
// Arrange
var collection = new ServiceCollection();
var controllerTypes = new[] { typeof(ControllerTypeA).GetTypeInfo(), typeof(TypeBController).GetTypeInfo() };
// Act
MvcServiceCollectionExtensions.WithControllersAsServices(collection,
controllerTypes);
// Assert
var services = collection.ToList();
Assert.Equal(4, services.Count);
Assert.Equal(typeof(ControllerTypeA), services[0].ServiceType);
Assert.Equal(typeof(ControllerTypeA), services[0].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[0].Lifetime);
Assert.Equal(typeof(TypeBController), services[1].ServiceType);
Assert.Equal(typeof(TypeBController), services[1].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[1].Lifetime);
Assert.Equal(typeof(IControllerActivator), services[2].ServiceType);
Assert.Equal(typeof(ServiceBasedControllerActivator), services[2].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[2].Lifetime);
Assert.Equal(typeof(IControllerTypeProvider), services[3].ServiceType);
var typeProvider = Assert.IsType<FixedSetControllerTypeProvider>(services[3].ImplementationInstance);
Assert.Equal(controllerTypes, typeProvider.ControllerTypes.OrderBy(c => c.Name));
Assert.Equal(ServiceLifetime.Singleton, services[3].Lifetime);
}
[Fact]
public void WithControllersAsServices_ScansControllersFromSpecifiedAssemblies()
{
// Arrange
var collection = new ServiceCollection();
var assemblies = new[] { GetType().Assembly };
var controllerTypes = new[] { typeof(ControllerTypeA), typeof(TypeBController) };
// Act
MvcServiceCollectionExtensions.WithControllersAsServices(collection, assemblies);
// Assert
var services = collection.ToList();
Assert.Equal(4, services.Count);
Assert.Equal(typeof(ControllerTypeA), services[0].ServiceType);
Assert.Equal(typeof(ControllerTypeA), services[0].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[0].Lifetime);
Assert.Equal(typeof(TypeBController), services[1].ServiceType);
Assert.Equal(typeof(TypeBController), services[1].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[1].Lifetime);
Assert.Equal(typeof(IControllerActivator), services[2].ServiceType);
Assert.Equal(typeof(ServiceBasedControllerActivator), services[2].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[2].Lifetime);
Assert.Equal(typeof(IControllerTypeProvider), services[3].ServiceType);
var typeProvider = Assert.IsType<FixedSetControllerTypeProvider>(services[3].ImplementationInstance);
Assert.Equal(controllerTypes, typeProvider.ControllerTypes.OrderBy(c => c.Name));
Assert.Equal(ServiceLifetime.Singleton, services[3].Lifetime);
}
// Some MVC services can be registered multiple times, for example, 'IConfigureOptions<MvcOptions>' can
// be registered by calling 'ConfigureMvc(...)' before the call to 'AddMvc()' in which case the options
// configuration is run in the order they were registered.
@ -323,36 +257,5 @@ namespace Microsoft.AspNet.Mvc
$"Found multiple instances of {implementationType} registered as {serviceType}");
}
}
private class CustomActivator : IControllerActivator
{
public object Create(ActionContext context, Type controllerType)
{
throw new NotImplementedException();
}
}
public class CustomTypeProvider : IControllerTypeProvider
{
public IEnumerable<TypeInfo> ControllerTypes { get; set; }
}
}
}
// These controllers are used to test the UseControllersAsServices implementation
// which REQUIRES that they be public top-level classes. To avoid having to stub out the
// implementation of this class to test it, they are just top level classes. Don't reuse
// these outside this test - find a better way or use nested classes to keep the tests
// independent.
namespace Microsoft.AspNet.Mvc.MvcServiceCollectionExtensionsTestControllers
{
public class ControllerTypeA : Controller
{
}
public class TypeBController
{
}
}

View File

@ -12,11 +12,9 @@ namespace ActionConstraintsWebSite
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.ConfigureMvc(options =>
{
options.AddXmlDataContractSerializerFormatter();
});
services
.AddMvc()
.AddXmlDataContractSerializerFormatters();
}
public void Configure(IApplicationBuilder app)

View File

@ -12,13 +12,11 @@ namespace ActionResultsWebSite
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddInstance(new GuidLookupService());
services
.AddMvc()
.AddXmlDataContractSerializerFormatters();
services.ConfigureMvc(options =>
{
options.AddXmlDataContractSerializerFormatter();
});
services.AddInstance(new GuidLookupService());
}
public void Configure(IApplicationBuilder app)

View File

@ -13,10 +13,7 @@ namespace ApiExplorerWebSite
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton<ApiExplorerDataFilter>();
services.ConfigureMvc(options =>
services.AddMvc(options =>
{
options.Filters.AddService(typeof(ApiExplorerDataFilter));
@ -28,6 +25,8 @@ namespace ApiExplorerWebSite
options.OutputFormatters.Add(new JsonOutputFormatter());
options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
});
services.AddSingleton<ApiExplorerDataFilter>();
}

View File

@ -12,9 +12,7 @@ namespace ApplicationModelWebSite
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.ConfigureMvc(options =>
services.AddMvc(options =>
{
options.Conventions.Add(new ApplicationDescription("Common Application Description"));
options.Conventions.Add(new ControllerLicenseConvention());

View File

@ -12,16 +12,12 @@ namespace BasicWebSite
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container
services.AddMvc();
services.AddSingleton<IActionDescriptorProvider, ActionDescriptorCreationCounter>();
services.ConfigureMvc(options =>
services.AddMvc(options =>
{
options.Conventions.Add(new ApplicationDescription("This is a basic website."));
});
services.AddSingleton<IActionDescriptorProvider, ActionDescriptorCreationCounter>();
}
public void Configure(IApplicationBuilder app)

View File

@ -12,8 +12,9 @@ namespace CompositeViewEngineWebSite
public void ConfigureServices(IServiceCollection services)
{
// Add a view engine as the first one in the list.
services.AddMvc()
.ConfigureMvcViews(options =>
services
.AddMvc()
.AddViewOptions(options =>
{
options.ViewEngines.Insert(0, new TestViewEngine());
});

View File

@ -12,12 +12,7 @@ namespace ContentNegotiationWebSite
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.ConfigureMvc(options =>
{
options.AddXmlDataContractSerializerFormatter();
});
services.AddMvc().AddXmlDataContractSerializerFormatters();
}
public void Configure(IApplicationBuilder app)

View File

@ -11,15 +11,14 @@ namespace ControllersFromServicesWebSite
{
public class Startup
{
// Set up application services
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.WithControllersAsServices(
new[]
{
typeof(TimeScheduleController).GetTypeInfo().Assembly
});
services
.AddMvc()
.AddControllersAsServices(new[]
{
typeof(TimeScheduleController).GetTypeInfo().Assembly
});
services.AddTransient<QueryValueService>();

View File

@ -14,18 +14,14 @@ namespace FormatFilterWebSite
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container
services.AddMvc();
services.ConfigureMvc(options =>
services.AddMvc(options =>
{
var formatFilter = new FormatFilterAttribute();
options.Filters.Add(formatFilter);
var customFormatter = new CustomFormatter("application/custom");
options.OutputFormatters.Add(customFormatter);
});
services.ConfigureMvc(options =>
{
options.FormatterMappings.SetMediaTypeMappingForFormat(
"custom",
MediaTypeHeaderValue.Parse("application/custom"));

View File

@ -9,28 +9,23 @@ namespace FormatterWebSite
{
public class Startup
{
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container
services.AddMvc();
services.Configure<MvcOptions>(options =>
services.AddMvc(options =>
{
options.ValidationExcludeFilters.Add(typeof(Developer));
options.ValidationExcludeFilters.Add(typeof(Supplier));
options.AddXmlDataContractSerializerFormatter();
options.InputFormatters.Add(new StringInputFormatter());
});
})
.AddXmlDataContractSerializerFormatters();
}
public void Configure(IApplicationBuilder app)
{
app.UseCultureReplacer();
// Add MVC to the request pipeline
app.UseMvc(routes =>
{
routes.MapRoute("ActionAsMethod", "{controller}/{action}",

View File

@ -9,12 +9,9 @@ namespace LocalizationWebSite
{
public class Startup
{
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container
services.AddMvc();
services.AddMvcLocalization();
services.AddMvc().AddViewLocalization();
// Adding TestStringLocalizerFactory since ResourceStringLocalizerFactory uses ResourceManager. DNX does
// not support getting non-enu resources from ResourceManager yet.
@ -26,8 +23,7 @@ namespace LocalizationWebSite
app.UseCultureReplacer();
app.UseRequestLocalization();
// Add MVC to the request pipeline
app.UseMvcWithDefaultRoute();
}
}

View File

@ -15,18 +15,18 @@ namespace ModelBindingWebSite
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container
services.AddMvc()
.Configure<MvcOptions>(m =>
{
m.MaxModelValidationErrors = 8;
m.ModelBinders.Insert(0, new TestBindingSourceModelBinder());
services
.AddMvc(m =>
{
m.MaxModelValidationErrors = 8;
m.ModelBinders.Insert(0, new TestBindingSourceModelBinder());
m.ValidationExcludeFilters.Add(typeof(Address));
m.AddXmlDataContractSerializerFormatter();
m.ValidationExcludeFilters.Add(typeof(Address));
// ModelMetadataController relies on additional values AdditionalValuesMetadataProvider provides.
m.ModelMetadataDetailsProviders.Add(new AdditionalValuesMetadataProvider());
});
// ModelMetadataController relies on additional values AdditionalValuesMetadataProvider provides.
m.ModelMetadataDetailsProviders.Add(new AdditionalValuesMetadataProvider());
})
.AddXmlDataContractSerializerFormatters();
services.AddSingleton<ICalculator, DefaultCalculator>();
services.AddSingleton<ITestService, TestService>();

View File

@ -11,34 +11,33 @@ namespace RazorWebSite
{
public class Startup
{
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container
services.AddMvc();
services
.AddMvc()
.AddRazorOptions(options =>
{
options.ViewLocationExpanders.Add(new CustomPartialDirectoryViewLocationExpander());
})
.AddViewOptions(options =>
{
options.HtmlHelperOptions.ClientValidationEnabled = false;
options.HtmlHelperOptions.Html5DateRenderingMode = Microsoft.AspNet.Mvc.Rendering.Html5DateRenderingMode.Rfc3339;
options.HtmlHelperOptions.IdAttributeDotReplacement = "!";
options.HtmlHelperOptions.ValidationMessageElement = "validationMessageElement";
options.HtmlHelperOptions.ValidationSummaryMessageElement = "validationSummaryElement";
})
.AddViewLocalization(LanguageViewLocationExpanderFormat.SubFolder);
services.AddTransient<InjectedHelper>();
services.AddTransient<TaskReturningService>();
services.AddTransient<FrameworkSpecificHelper>();
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add(new CustomPartialDirectoryViewLocationExpander());
});
services.ConfigureMvcViews(options =>
{
options.HtmlHelperOptions.ClientValidationEnabled = false;
options.HtmlHelperOptions.Html5DateRenderingMode = Microsoft.AspNet.Mvc.Rendering.Html5DateRenderingMode.Rfc3339;
options.HtmlHelperOptions.IdAttributeDotReplacement = "!";
options.HtmlHelperOptions.ValidationMessageElement = "validationMessageElement";
options.HtmlHelperOptions.ValidationSummaryMessageElement = "validationSummaryElement";
});
services.AddMvcLocalization(LanguageViewLocationExpanderFormat.SubFolder);
}
public void Configure(IApplicationBuilder app)
{
app.UseRequestLocalization();
// Add MVC to the request pipeline
app.UseMvcWithDefaultRoute();
}
}

View File

@ -9,11 +9,9 @@ namespace ResponseCacheWebSite
{
public class Startup
{
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.ConfigureMvc(options =>
services.AddMvc(options =>
{
options.CacheProfiles.Add(
"PublicCache30Sec", new CacheProfile
@ -44,10 +42,7 @@ namespace ResponseCacheWebSite
Location = ResponseCacheLocation.Any,
VaryByHeader = "Accept"
});
});
services.ConfigureMvc(options =>
{
options.Filters.Add(new ResponseCacheFilter(new CacheProfile
{
NoStore = true,

View File

@ -11,19 +11,17 @@ namespace ValueProvidersWebSite
{
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container
services.AddMvc()
.Configure<MvcOptions>(options =>
{
options.ValueProviderFactories.Insert(1, new CustomValueProviderFactory());
});
services
.AddMvc(options =>
{
options.ValueProviderFactories.Insert(1, new CustomValueProviderFactory());
});
}
public void Configure(IApplicationBuilder app)
{
app.UseCultureReplacer();
// Add MVC to the request pipeline
app.UseMvcWithDefaultRoute();
}
}

View File

@ -12,8 +12,7 @@ namespace WebApiCompatShimWebSite
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container
services.AddMvc();
services.AddWebApiConventions();
services.AddMvc().AddWebApiConventions();
}
public void Configure(IApplicationBuilder app)