ControllerActivator should be able to use controllers registered as
services * Added WithControllersFromServiceProvider that replaces the default controller activator with a service based one. * Move activation to DefaultControllerFactory * Modify [Activate] behavior so that it no longer activates services. Use [FromService] attribute to hydrate services Fixes #1707
This commit is contained in:
parent
7cb6c1065c
commit
e1e43e1e8c
42
Mvc.sln
42
Mvc.sln
|
|
@ -132,6 +132,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Xml.Te
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "FormatFilterWebSite", "test\WebSites\FormatFilterWebSite\FormatFilterWebSite.kproj", "{AC9BE567-540E-4C70-90C2-AAF021307A80}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ControllersFromServicesWebSite", "test\WebSites\ControllersFromServicesWebSite\ControllersFromServicesWebSite.kproj", "{983741B2-4424-4ED1-9B03-7675A67230C8}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ControllersFromServicesClassLibrary", "test\WebSites\ControllersFromServicesClassLibrary\ControllersFromServicesClassLibrary.kproj", "{551DC89E-2A13-4CF2-83D7-1ADD802443D5}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "RazorCompilerCacheWebSite", "test\WebSites\RazorCompilerCacheWebSite\RazorCompilerCacheWebSite.kproj", "{42C5D417-4060-48F4-BB28-E9E179007779}"
|
||||
EndProject
|
||||
Global
|
||||
|
|
@ -732,6 +736,18 @@ Global
|
|||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Release|x86.Build.0 = Release|Any CPU
|
||||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Release|x86.Build.0 = Release|Any CPU
|
||||
{22019146-BDFA-442E-8C8E-345FB9644578}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{22019146-BDFA-442E-8C8E-345FB9644578}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{22019146-BDFA-442E-8C8E-345FB9644578}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
|
|
@ -756,6 +772,30 @@ Global
|
|||
{AC9BE567-540E-4C70-90C2-AAF021307A80}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{AC9BE567-540E-4C70-90C2-AAF021307A80}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{AC9BE567-540E-4C70-90C2-AAF021307A80}.Release|x86.Build.0 = Release|Any CPU
|
||||
{983741B2-4424-4ED1-9B03-7675A67230C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{983741B2-4424-4ED1-9B03-7675A67230C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{983741B2-4424-4ED1-9B03-7675A67230C8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{983741B2-4424-4ED1-9B03-7675A67230C8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{983741B2-4424-4ED1-9B03-7675A67230C8}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{983741B2-4424-4ED1-9B03-7675A67230C8}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{983741B2-4424-4ED1-9B03-7675A67230C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{983741B2-4424-4ED1-9B03-7675A67230C8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{983741B2-4424-4ED1-9B03-7675A67230C8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{983741B2-4424-4ED1-9B03-7675A67230C8}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{983741B2-4424-4ED1-9B03-7675A67230C8}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{983741B2-4424-4ED1-9B03-7675A67230C8}.Release|x86.Build.0 = Release|Any CPU
|
||||
{551DC89E-2A13-4CF2-83D7-1ADD802443D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{551DC89E-2A13-4CF2-83D7-1ADD802443D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{551DC89E-2A13-4CF2-83D7-1ADD802443D5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{551DC89E-2A13-4CF2-83D7-1ADD802443D5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{551DC89E-2A13-4CF2-83D7-1ADD802443D5}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{551DC89E-2A13-4CF2-83D7-1ADD802443D5}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{551DC89E-2A13-4CF2-83D7-1ADD802443D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{551DC89E-2A13-4CF2-83D7-1ADD802443D5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{551DC89E-2A13-4CF2-83D7-1ADD802443D5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{551DC89E-2A13-4CF2-83D7-1ADD802443D5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{551DC89E-2A13-4CF2-83D7-1ADD802443D5}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{551DC89E-2A13-4CF2-83D7-1ADD802443D5}.Release|x86.Build.0 = Release|Any CPU
|
||||
{42C5D417-4060-48F4-BB28-E9E179007779}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{42C5D417-4060-48F4-BB28-E9E179007779}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{42C5D417-4060-48F4-BB28-E9E179007779}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
|
|
@ -832,6 +872,8 @@ Global
|
|||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{22019146-BDFA-442E-8C8E-345FB9644578} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||
{AC9BE567-540E-4C70-90C2-AAF021307A80} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{983741B2-4424-4ED1-9B03-7675A67230C8} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{551DC89E-2A13-4CF2-83D7-1ADD802443D5} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{42C5D417-4060-48F4-BB28-E9E179007779} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ namespace MvcSample.Web
|
|||
return View("MyView", user);
|
||||
}
|
||||
|
||||
[Activate]
|
||||
[FromServices]
|
||||
public IHostingEnvironment HostingEnvironment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ using System.Linq;
|
|||
using System.Reflection;
|
||||
using Microsoft.AspNet.Mvc.Description;
|
||||
using Microsoft.AspNet.Mvc.Filters;
|
||||
using Microsoft.AspNet.Mvc.Logging;
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.Framework.Logging;
|
||||
|
||||
|
|
@ -34,11 +33,6 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
/// <inheritdoc />
|
||||
public ControllerModel BuildControllerModel([NotNull] TypeInfo typeInfo)
|
||||
{
|
||||
if (!IsController(typeInfo))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var controllerModel = CreateControllerModel(typeInfo);
|
||||
|
||||
foreach (var methodInfo in typeInfo.AsType().GetMethods())
|
||||
|
|
@ -57,54 +51,6 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
return controllerModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <c>true</c> if the <paramref name="typeInfo"/> is a controller. Otherwise <c>false</c>.
|
||||
/// </summary>
|
||||
/// <param name="typeInfo">The <see cref="TypeInfo"/>.</param>
|
||||
/// <returns><c>true</c> if the <paramref name="typeInfo"/> is a controller. Otherwise <c>false</c>.</returns>
|
||||
/// <remarks>
|
||||
/// Override this method to provide custom logic to determine which types are considered controllers.
|
||||
/// </remarks>
|
||||
protected virtual bool IsController([NotNull] TypeInfo typeInfo)
|
||||
{
|
||||
var status = ControllerStatus.IsController;
|
||||
|
||||
if (!typeInfo.IsClass)
|
||||
{
|
||||
status |= ControllerStatus.IsNotAClass;
|
||||
}
|
||||
if (typeInfo.IsAbstract)
|
||||
{
|
||||
status |= ControllerStatus.IsAbstract;
|
||||
}
|
||||
// We only consider public top-level classes as controllers. IsPublic returns false for nested
|
||||
// classes, regardless of visibility modifiers
|
||||
if (!typeInfo.IsPublic)
|
||||
{
|
||||
status |= ControllerStatus.IsNotPublicOrTopLevel;
|
||||
}
|
||||
if (typeInfo.ContainsGenericParameters)
|
||||
{
|
||||
status |= ControllerStatus.ContainsGenericParameters;
|
||||
}
|
||||
if (typeInfo.Name.Equals("Controller", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
status |= ControllerStatus.NameIsController;
|
||||
}
|
||||
if (!typeInfo.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) &&
|
||||
!typeof(Controller).GetTypeInfo().IsAssignableFrom(typeInfo))
|
||||
{
|
||||
status |= ControllerStatus.DoesNotEndWithControllerAndIsNotAssignable;
|
||||
}
|
||||
if (_logger.IsEnabled(LogLevel.Verbose))
|
||||
{
|
||||
_logger.WriteVerbose(new IsControllerValues(
|
||||
typeInfo.AsType(),
|
||||
status));
|
||||
}
|
||||
return status == ControllerStatus.IsController;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="ControllerModel"/> for the given <see cref="TypeInfo"/>.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -100,10 +100,10 @@ namespace Microsoft.AspNet.Mvc
|
|||
[Activate]
|
||||
public ActionBindingContext BindingContext { get; set; }
|
||||
|
||||
[Activate]
|
||||
[FromServices]
|
||||
public IModelMetadataProvider MetadataProvider { get; set; }
|
||||
|
||||
[Activate]
|
||||
[FromServices]
|
||||
public IUrlHelper Url { get; set; }
|
||||
|
||||
public IPrincipal User
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.Mvc.ApplicationModels;
|
||||
using Microsoft.AspNet.Mvc.Filters;
|
||||
using Microsoft.AspNet.Mvc.Logging;
|
||||
|
|
@ -15,18 +14,18 @@ namespace Microsoft.AspNet.Mvc
|
|||
public class ControllerActionDescriptorProvider : IActionDescriptorProvider
|
||||
{
|
||||
private readonly IControllerModelBuilder _applicationModelBuilder;
|
||||
private readonly IAssemblyProvider _assemblyProvider;
|
||||
private readonly IControllerTypeProvider _controllerTypeProvider;
|
||||
private readonly IReadOnlyList<IFilter> _globalFilters;
|
||||
private readonly IEnumerable<IApplicationModelConvention> _conventions;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public ControllerActionDescriptorProvider([NotNull] IAssemblyProvider assemblyProvider,
|
||||
public ControllerActionDescriptorProvider([NotNull] IControllerTypeProvider controllerTypeProvider,
|
||||
[NotNull] IControllerModelBuilder applicationModelBuilder,
|
||||
[NotNull] IGlobalFilterProvider globalFilters,
|
||||
[NotNull] IOptions<MvcOptions> optionsAccessor,
|
||||
[NotNull] ILoggerFactory loggerFactory)
|
||||
{
|
||||
_assemblyProvider = assemblyProvider;
|
||||
_controllerTypeProvider = controllerTypeProvider;
|
||||
_applicationModelBuilder = applicationModelBuilder;
|
||||
_globalFilters = globalFilters.Filters;
|
||||
_conventions = optionsAccessor.Options.Conventions;
|
||||
|
|
@ -66,17 +65,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
applicationModel.Filters.Add(filter);
|
||||
}
|
||||
|
||||
var assemblies = _assemblyProvider.CandidateAssemblies;
|
||||
var types = assemblies.SelectMany(a => a.DefinedTypes);
|
||||
if (_logger.IsEnabled(LogLevel.Verbose))
|
||||
{
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
_logger.WriteVerbose(new AssemblyValues(assembly));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var type in types)
|
||||
foreach (var type in _controllerTypeProvider.ControllerTypes)
|
||||
{
|
||||
var controllerModel = _applicationModelBuilder.BuildControllerModel(type);
|
||||
if (controllerModel != null)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
get
|
||||
{
|
||||
return GetCandidateLibraries().SelectMany(l => l.LoadableAssemblies).Select(Load);
|
||||
return GetCandidateLibraries().SelectMany(l => l.LoadableAssemblies)
|
||||
.Select(Load);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,106 +3,26 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the <see cref="IControllerActivator"/> that is registered by default.
|
||||
/// <see cref="IControllerActivator"/> that uses type activation to create controllers.
|
||||
/// </summary>
|
||||
public class DefaultControllerActivator : IControllerActivator
|
||||
{
|
||||
private readonly Func<Type, PropertyActivator<ActionContext>[]> _getPropertiesToActivate;
|
||||
private readonly IDictionary<Type, Func<ActionContext, object>> _valueAccessorLookup;
|
||||
private readonly ConcurrentDictionary<Type, PropertyActivator<ActionContext>[]> _injectActions;
|
||||
private static readonly Func<Type, ObjectFactory> _createControllerFactory =
|
||||
type => ActivatorUtilities.CreateFactory(type, Type.EmptyTypes);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the DefaultControllerActivator class.
|
||||
/// </summary>
|
||||
public DefaultControllerActivator()
|
||||
private readonly ConcurrentDictionary<Type, ObjectFactory> _controllerFactories =
|
||||
new ConcurrentDictionary<Type, ObjectFactory>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public object Create([NotNull] ActionContext actionContext, [NotNull] Type controllerType)
|
||||
{
|
||||
_valueAccessorLookup = CreateValueAccessorLookup();
|
||||
_injectActions = new ConcurrentDictionary<Type, PropertyActivator<ActionContext>[]>();
|
||||
_getPropertiesToActivate = type =>
|
||||
PropertyActivator<ActionContext>.GetPropertiesToActivate(type,
|
||||
typeof(ActivateAttribute),
|
||||
CreateActivateInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Activates the specified controller by using the specified action context.
|
||||
/// </summary>
|
||||
/// <param name="controller">The controller to activate.</param>
|
||||
/// <param name="context">The context of the executing action.</param>
|
||||
public virtual void Activate([NotNull] object controller, [NotNull] ActionContext context)
|
||||
{
|
||||
var controllerType = controller.GetType();
|
||||
var controllerTypeInfo = controllerType.GetTypeInfo();
|
||||
if (controllerTypeInfo.IsValueType)
|
||||
{
|
||||
var message = Resources.FormatValueTypesCannotBeActivated(GetType().FullName);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
var propertiesToActivate = _injectActions.GetOrAdd(controllerType,
|
||||
_getPropertiesToActivate);
|
||||
|
||||
for (var i = 0; i < propertiesToActivate.Length; i++)
|
||||
{
|
||||
var activateInfo = propertiesToActivate[i];
|
||||
activateInfo.Activate(controller, context);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual IDictionary<Type, Func<ActionContext, object>> CreateValueAccessorLookup()
|
||||
{
|
||||
var dictionary = new Dictionary<Type, Func<ActionContext, object>>
|
||||
{
|
||||
{ typeof(ActionContext), (context) => context },
|
||||
{ typeof(HttpContext), (context) => context.HttpContext },
|
||||
{ typeof(HttpRequest), (context) => context.HttpContext.Request },
|
||||
{ typeof(HttpResponse), (context) => context.HttpContext.Response },
|
||||
{
|
||||
typeof(ViewDataDictionary),
|
||||
(context) =>
|
||||
{
|
||||
var serviceProvider = context.HttpContext.RequestServices;
|
||||
return new ViewDataDictionary(
|
||||
serviceProvider.GetRequiredService<IModelMetadataProvider>(),
|
||||
context.ModelState);
|
||||
}
|
||||
},
|
||||
{
|
||||
typeof(ActionBindingContext),
|
||||
(context) =>
|
||||
{
|
||||
var serviceProvider = context.HttpContext.RequestServices;
|
||||
var accessor = serviceProvider.GetRequiredService<IScopedInstance<ActionBindingContext>>();
|
||||
return accessor.Value;
|
||||
}
|
||||
}
|
||||
};
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
private PropertyActivator<ActionContext> CreateActivateInfo(
|
||||
PropertyInfo property)
|
||||
{
|
||||
Func<ActionContext, object> valueAccessor;
|
||||
if (!_valueAccessorLookup.TryGetValue(property.PropertyType, out valueAccessor))
|
||||
{
|
||||
valueAccessor = (actionContext) =>
|
||||
{
|
||||
var serviceProvider = actionContext.HttpContext.RequestServices;
|
||||
return serviceProvider.GetRequiredService(property.PropertyType);
|
||||
};
|
||||
}
|
||||
|
||||
return new PropertyActivator<ActionContext>(property, valueAccessor);
|
||||
var factory = _controllerFactories.GetOrAdd(controllerType, _createControllerFactory);
|
||||
return factory(actionContext.HttpContext.RequestServices, arguments: null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,27 +2,43 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Default implementation for <see cref="IControllerFactory"/>.
|
||||
/// </summary>
|
||||
public class DefaultControllerFactory : IControllerFactory
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ITypeActivator _typeActivator;
|
||||
private readonly IControllerActivator _controllerActivator;
|
||||
private readonly IDictionary<Type, Func<ActionContext, object>> _valueAccessorLookup;
|
||||
private readonly ConcurrentDictionary<Type, PropertyActivator<ActionContext>[]> _activateActions;
|
||||
private readonly Func<Type, PropertyActivator<ActionContext>[]> _getPropertiesToActivate;
|
||||
private readonly Func<Type, Func<ActionContext, object>> _getRequiredService = GetRequiredService;
|
||||
|
||||
public DefaultControllerFactory(IServiceProvider serviceProvider,
|
||||
ITypeActivator typeActivator,
|
||||
IControllerActivator controllerActivator)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="DefaultControllerFactory"/>.
|
||||
/// </summary>
|
||||
/// <param name="controllerActivator"><see cref="IControllerActivator"/> used to create controller
|
||||
/// instances.</param>
|
||||
public DefaultControllerFactory(IControllerActivator controllerActivator)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_typeActivator = typeActivator;
|
||||
_controllerActivator = controllerActivator;
|
||||
_valueAccessorLookup = CreateValueAccessorLookup();
|
||||
_activateActions = new ConcurrentDictionary<Type, PropertyActivator<ActionContext>[]>();
|
||||
_getPropertiesToActivate = GetPropertiesToActivate;
|
||||
}
|
||||
|
||||
public object CreateController(ActionContext actionContext)
|
||||
/// <inheritdoc />
|
||||
public object CreateController([NotNull] ActionContext actionContext)
|
||||
{
|
||||
var actionDescriptor = actionContext.ActionDescriptor as ControllerActionDescriptor;
|
||||
if (actionDescriptor == null)
|
||||
|
|
@ -33,15 +49,14 @@ namespace Microsoft.AspNet.Mvc
|
|||
nameof(actionContext));
|
||||
}
|
||||
|
||||
var controller = _typeActivator.CreateInstance(
|
||||
_serviceProvider,
|
||||
actionDescriptor.ControllerTypeInfo.AsType());
|
||||
|
||||
_controllerActivator.Activate(controller, actionContext);
|
||||
var controllerType = actionDescriptor.ControllerTypeInfo.AsType();
|
||||
var controller = _controllerActivator.Create(actionContext, controllerType);
|
||||
ActivateProperties(controller, actionContext);
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ReleaseController(object controller)
|
||||
{
|
||||
var disposableController = controller as IDisposable;
|
||||
|
|
@ -51,5 +66,111 @@ namespace Microsoft.AspNet.Mvc
|
|||
disposableController.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Activates the specified controller using the specified action context.
|
||||
/// </summary>
|
||||
/// <param name="controller">The controller to activate.</param>
|
||||
/// <param name="context">The context of the executing action.</param>
|
||||
protected virtual void ActivateProperties([NotNull] object controller, [NotNull] ActionContext context)
|
||||
{
|
||||
var controllerType = controller.GetType();
|
||||
var controllerTypeInfo = controllerType.GetTypeInfo();
|
||||
if (controllerTypeInfo.IsValueType)
|
||||
{
|
||||
var message = Resources.FormatValueTypesCannotBeActivated(GetType().FullName);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
var propertiesToActivate = _activateActions.GetOrAdd(controllerType,
|
||||
_getPropertiesToActivate);
|
||||
|
||||
for (var i = 0; i < propertiesToActivate.Length; i++)
|
||||
{
|
||||
var activateInfo = propertiesToActivate[i];
|
||||
activateInfo.Activate(controller, context);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="IDictionary{TKey, TValue}"/> of property types to delegates used to activate
|
||||
/// controller properties annotated with <see cref="ActivateAttribute"/>.
|
||||
/// </summary>
|
||||
/// <returns>A dictionary containing the property type to activator delegate mapping.</returns>
|
||||
/// <remarks>Override this method to provide custom activation behavior for controller properties
|
||||
/// annotated with <see cref="ActivateAttribute"/>.</remarks>
|
||||
protected virtual IDictionary<Type, Func<ActionContext, object>> CreateValueAccessorLookup()
|
||||
{
|
||||
var dictionary = new Dictionary<Type, Func<ActionContext, object>>
|
||||
{
|
||||
{ typeof(ActionContext), (context) => context },
|
||||
{ typeof(HttpContext), (context) => context.HttpContext },
|
||||
{ typeof(HttpRequest), (context) => context.HttpContext.Request },
|
||||
{ typeof(HttpResponse), (context) => context.HttpContext.Response },
|
||||
{
|
||||
typeof(ViewDataDictionary),
|
||||
(context) =>
|
||||
{
|
||||
var serviceProvider = context.HttpContext.RequestServices;
|
||||
return new ViewDataDictionary(
|
||||
serviceProvider.GetRequiredService<IModelMetadataProvider>(),
|
||||
context.ModelState);
|
||||
}
|
||||
},
|
||||
{
|
||||
typeof(ActionBindingContext),
|
||||
(context) =>
|
||||
{
|
||||
var serviceProvider = context.HttpContext.RequestServices;
|
||||
var accessor = serviceProvider.GetRequiredService<IScopedInstance<ActionBindingContext>>();
|
||||
return accessor.Value;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
private PropertyActivator<ActionContext>[] GetPropertiesToActivate(Type type)
|
||||
{
|
||||
var activatorsForActivateProperties = PropertyActivator<ActionContext>.GetPropertiesToActivate(
|
||||
type,
|
||||
typeof(ActivateAttribute),
|
||||
CreateActivateInfo);
|
||||
var activatorsForFromServiceProperties = PropertyActivator<ActionContext>.GetPropertiesToActivate(
|
||||
type,
|
||||
typeof(FromServicesAttribute),
|
||||
CreateFromServicesInfo);
|
||||
|
||||
return Enumerable.Concat(activatorsForActivateProperties, activatorsForFromServiceProperties)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private PropertyActivator<ActionContext> CreateActivateInfo(
|
||||
PropertyInfo property)
|
||||
{
|
||||
Func<ActionContext, object> valueAccessor;
|
||||
if (!_valueAccessorLookup.TryGetValue(property.PropertyType, out valueAccessor))
|
||||
{
|
||||
var message = Resources.FormatControllerFactory_PropertyCannotBeActivated(
|
||||
property.Name,
|
||||
property.DeclaringType.FullName);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
return new PropertyActivator<ActionContext>(property, valueAccessor);
|
||||
}
|
||||
|
||||
private PropertyActivator<ActionContext> CreateFromServicesInfo(
|
||||
PropertyInfo property)
|
||||
{
|
||||
var valueAccessor = _getRequiredService(property.PropertyType);
|
||||
return new PropertyActivator<ActionContext>(property, valueAccessor);
|
||||
}
|
||||
|
||||
private static Func<ActionContext, object> GetRequiredService(Type propertyType)
|
||||
{
|
||||
return actionContext => actionContext.HttpContext.RequestServices.GetRequiredService(propertyType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.Logging;
|
||||
using Microsoft.Framework.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="IControllerTypeProvider"/> that identifies controller types from assemblies
|
||||
/// specified by the registered <see cref="IAssemblyProvider"/>.
|
||||
/// </summary>
|
||||
public class DefaultControllerTypeProvider : IControllerTypeProvider
|
||||
{
|
||||
private readonly IAssemblyProvider _assemblyProvider;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="DefaultControllerTypeProvider"/>.
|
||||
/// </summary>
|
||||
/// <param name="assemblyProvider"><see cref="IAssemblyProvider"/> that provides assemblies to look for
|
||||
/// controllers in.</param>
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||
public DefaultControllerTypeProvider(IAssemblyProvider assemblyProvider,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
_assemblyProvider = assemblyProvider;
|
||||
_logger = loggerFactory.Create<DefaultControllerTypeProvider>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual IEnumerable<TypeInfo> ControllerTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
var assemblies = _assemblyProvider.CandidateAssemblies;
|
||||
if (_logger.IsEnabled(LogLevel.Verbose))
|
||||
{
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
_logger.WriteVerbose(new AssemblyValues(assembly));
|
||||
}
|
||||
}
|
||||
|
||||
var types = assemblies.SelectMany(a => a.DefinedTypes);
|
||||
return types.Where(IsController);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <c>true</c> if the <paramref name="typeInfo"/> is a controller. Otherwise <c>false</c>.
|
||||
/// </summary>
|
||||
/// <param name="typeInfo">The <see cref="TypeInfo"/>.</param>
|
||||
/// <returns><c>true</c> if the <paramref name="typeInfo"/> is a controller. Otherwise <c>false</c>.</returns>
|
||||
protected internal virtual bool IsController([NotNull] TypeInfo typeInfo)
|
||||
{
|
||||
if (!typeInfo.IsClass)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (typeInfo.IsAbstract)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// We only consider public top-level classes as controllers. IsPublic returns false for nested
|
||||
// classes, regardless of visibility modifiers
|
||||
if (!typeInfo.IsPublic)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (typeInfo.ContainsGenericParameters)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (typeInfo.Name.Equals("Controller", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!typeInfo.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) &&
|
||||
!typeof(Controller).GetTypeInfo().IsAssignableFrom(typeInfo))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="IAssemblyProvider"/> with a fixed set of candidate assemblies.
|
||||
/// </summary>
|
||||
public class FixedSetAssemblyProvider : IAssemblyProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the list of candidate assemblies.
|
||||
/// </summary>
|
||||
public IList<Assembly> CandidateAssemblies { get; } = new List<Assembly>();
|
||||
|
||||
IEnumerable<Assembly> IAssemblyProvider.CandidateAssemblies => CandidateAssemblies;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="IControllerTypeProvider"/> with a fixed set of types that are used as controllers.
|
||||
/// </summary>
|
||||
public class FixedSetControllerTypeProvider : IControllerTypeProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="FixedSetControllerTypeProvider"/>.
|
||||
/// </summary>
|
||||
public FixedSetControllerTypeProvider()
|
||||
: this(Enumerable.Empty<TypeInfo>())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="FixedSetControllerTypeProvider"/>.
|
||||
/// </summary>
|
||||
/// <param name="controllerTypes">The sequence of controller <see cref="TypeInfo"/>.</param>
|
||||
public FixedSetControllerTypeProvider([NotNull] IEnumerable<TypeInfo> controllerTypes)
|
||||
{
|
||||
ControllerTypes = new List<TypeInfo>(controllerTypes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of controller <see cref="TypeInfo"/>s.
|
||||
/// </summary>
|
||||
public IList<TypeInfo> ControllerTypes { get; }
|
||||
|
||||
IEnumerable<TypeInfo> IControllerTypeProvider.ControllerTypes => ControllerTypes;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,8 +6,16 @@ using System.Reflection;
|
|||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the contract for discovering assemblies that may contain Mvc specific types such as controllers,
|
||||
/// view components and precompiled views.
|
||||
/// </summary>
|
||||
public interface IAssemblyProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the sequence of candidate <see cref="Assembly"/>ies that the application
|
||||
/// uses for discovery of Mvc specific types.
|
||||
/// </summary>
|
||||
IEnumerable<Assembly> CandidateAssemblies { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods to activate an instantiated controller.
|
||||
/// Provides methods to create a controller.
|
||||
/// </summary>
|
||||
public interface IControllerActivator
|
||||
{
|
||||
/// <summary>
|
||||
/// When implemented in a type, activates an instantiated controller.
|
||||
/// Creates a controller.
|
||||
/// </summary>
|
||||
/// <param name="controller">The controller to activate.</param>
|
||||
/// <param name="context">The <see cref="ActionContext"/> for the executing action.</param>
|
||||
void Activate(object controller, ActionContext context);
|
||||
object Create(ActionContext context, Type controllerType);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,9 +3,22 @@
|
|||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods for creation and disposal of controllers.
|
||||
/// </summary>
|
||||
public interface IControllerFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new controller for the specified <paramref name="actionContext"/>.
|
||||
/// </summary>
|
||||
/// <param name="actionContext"><see cref="ActionContext"/> for the action to execute.</param>
|
||||
/// <returns>The controller.</returns>
|
||||
object CreateController(ActionContext actionContext);
|
||||
|
||||
/// <summary>
|
||||
/// Releases a controller instance.
|
||||
/// </summary>
|
||||
/// <param name="controller">The controller.</param>
|
||||
void ReleaseController(object controller);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods for discovery of controller types.
|
||||
/// </summary>
|
||||
public interface IControllerTypeProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a <see cref="IEnumerable{T}"/> of controller <see cref="TypeInfo"/>s.
|
||||
/// </summary>
|
||||
IEnumerable<TypeInfo> ControllerTypes { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the status of a class during controller discovery.
|
||||
/// All values except 0 represent a reason why a type is not a controller.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum ControllerStatus
|
||||
{
|
||||
IsController = 0,
|
||||
IsNotAClass = 1,
|
||||
IsNotPublicOrTopLevel = 2,
|
||||
IsAbstract = 4,
|
||||
ContainsGenericParameters = 8,
|
||||
// The name of the controller class is "Controller"
|
||||
NameIsController = 16,
|
||||
DoesNotEndWithControllerAndIsNotAssignable = 32
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.Framework.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Logged to indicate the state of a class during controller discovery. Logs the type
|
||||
/// of the controller as well as the <see cref="ControllerStatus"/>.
|
||||
/// </summary>
|
||||
public class IsControllerValues : LoggerStructureBase
|
||||
{
|
||||
public IsControllerValues(Type type, ControllerStatus status)
|
||||
{
|
||||
Type = type;
|
||||
Status = status;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="System.Type"/> of the potential <see cref="Controller"/> class.
|
||||
/// </summary>
|
||||
public Type Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ControllerStatus"/> of the <see cref="Type"/>.
|
||||
/// </summary>
|
||||
public ControllerStatus Status { get; }
|
||||
|
||||
public override string Format()
|
||||
{
|
||||
return LogFormatter.FormatStructure(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1642,6 +1642,22 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("Format_NotValid"), p0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The property '{0}' on controller '{1}' cannot be activated.
|
||||
/// </summary>
|
||||
internal static string ControllerFactory_PropertyCannotBeActivated
|
||||
{
|
||||
get { return GetString("ControllerFactory_PropertyCannotBeActivated"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The property '{0}' on controller '{1}' cannot be activated.
|
||||
/// </summary>
|
||||
internal static string FormatControllerFactory_PropertyCannotBeActivated(object p0, object p1)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("ControllerFactory_PropertyCannotBeActivated"), p0, p1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// No URL for remote validation could be found.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -433,6 +433,9 @@
|
|||
<data name="Format_NotValid" xml:space="preserve">
|
||||
<value>The format provided is invalid '{0}'. A format must be a non-empty file-extension, optionally prefixed with a '.' character.</value>
|
||||
</data>
|
||||
<data name="ControllerFactory_PropertyCannotBeActivated" xml:space="preserve">
|
||||
<value>The property '{0}' on controller '{1}' cannot be activated.</value>
|
||||
</data>
|
||||
<data name="RemoteAttribute_NoUrlFound" xml:space="preserve">
|
||||
<value>No URL for remote validation could be found.</value>
|
||||
</data>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.Framework.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="IControllerActivator"/> that retrieves controllers as services from the request's
|
||||
/// <see cref="IServiceProvider"/>.
|
||||
/// </summary>
|
||||
public class ServiceBasedControllerActivator : IControllerActivator
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public object Create([NotNull] ActionContext actionContext, [NotNull] Type controllerType)
|
||||
{
|
||||
return actionContext.HttpContext.RequestServices.GetRequiredService(controllerType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -51,7 +51,7 @@ namespace System.Web.Http
|
|||
/// Gets the <see cref="IModelMetadataProvider"/>.
|
||||
/// </summary>
|
||||
/// <remarks>The setter is intended for unit testing purposes only.</remarks>
|
||||
[Activate]
|
||||
[FromServices]
|
||||
public IModelMetadataProvider MetadataProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -91,7 +91,7 @@ namespace System.Web.Http
|
|||
/// Gets a factory used to generate URLs to other APIs.
|
||||
/// </summary>
|
||||
/// <remarks>The setter is intended for unit testing purposes only.</remarks>
|
||||
[Activate]
|
||||
[FromServices]
|
||||
public IUrlHelper Url { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -2,9 +2,13 @@
|
|||
// 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.Routing;
|
||||
using Microsoft.Framework.ConfigurationModel;
|
||||
using Microsoft.Framework.Logging;
|
||||
|
||||
namespace Microsoft.Framework.DependencyInjection
|
||||
{
|
||||
|
|
@ -36,6 +40,92 @@ namespace Microsoft.Framework.DependencyInjection
|
|||
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)
|
||||
{
|
||||
return WithControllersAsServices(services, controllerTypes, configuration: null);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <param name="configuration">The application's <see cref="IConfiguration"/>.</param>
|
||||
/// <returns>The <see cref="IServiceCollection"/>.</returns>
|
||||
public static IServiceCollection WithControllersAsServices(
|
||||
[NotNull] this IServiceCollection services,
|
||||
[NotNull] IEnumerable<Type> controllerTypes,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
var controllerTypeProvider = new FixedSetControllerTypeProvider();
|
||||
foreach (var type in controllerTypes)
|
||||
{
|
||||
services.AddTransient(type);
|
||||
controllerTypeProvider.ControllerTypes.Add(type.GetTypeInfo());
|
||||
}
|
||||
|
||||
var describer = new ServiceDescriber(configuration);
|
||||
services.Replace(describer.Transient<IControllerActivator, ServiceBasedControllerActivator>());
|
||||
services.Replace(describer.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)
|
||||
{
|
||||
return WithControllersAsServices(services,
|
||||
controllerAssemblies,
|
||||
configuration: null);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <param name="configuration">The application's <see cref="IConfiguration"/>.</param>
|
||||
/// <returns>The <see cref="IServiceCollection"/>.</returns>
|
||||
public static IServiceCollection WithControllersAsServices(
|
||||
[NotNull] this IServiceCollection services,
|
||||
[NotNull] IEnumerable<Assembly> controllerAssemblies,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
var assemblyProvider = new FixedSetAssemblyProvider();
|
||||
foreach (var assembly in controllerAssemblies)
|
||||
{
|
||||
assemblyProvider.CandidateAssemblies.Add(assembly);
|
||||
}
|
||||
var loggerFactory = NullLoggerFactory.Instance;
|
||||
var controllerTypeProvider = new DefaultControllerTypeProvider(assemblyProvider, loggerFactory);
|
||||
var controllerTypes = controllerTypeProvider.ControllerTypes;
|
||||
|
||||
return WithControllersAsServices(services,
|
||||
controllerTypes.Select(type => type.AsType()),
|
||||
configuration);
|
||||
}
|
||||
|
||||
private static void ConfigureDefaultServices(IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddOptions(configuration);
|
||||
|
|
|
|||
|
|
@ -42,11 +42,12 @@ namespace Microsoft.AspNet.Mvc
|
|||
// Core action discovery, filters and action execution.
|
||||
|
||||
// These are consumed only when creating action descriptors, then they can be de-allocated
|
||||
yield return describe.Transient<IControllerTypeProvider, DefaultControllerTypeProvider>();
|
||||
yield return describe.Transient<IControllerModelBuilder, DefaultControllerModelBuilder>();
|
||||
yield return describe.Transient<IActionModelBuilder, DefaultActionModelBuilder>();
|
||||
|
||||
// This accesses per-request services to activate the controller
|
||||
yield return describe.Transient<IControllerFactory, DefaultControllerFactory>();
|
||||
// This has a cache, so it needs to be a singleton
|
||||
yield return describe.Singleton<IControllerFactory, DefaultControllerFactory>();
|
||||
|
||||
// This has a cache, so it needs to be a singleton
|
||||
yield return describe.Singleton<IControllerActivator, DefaultControllerActivator>();
|
||||
|
|
|
|||
|
|
@ -1,176 +1,22 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNet.Mvc.Filters;
|
||||
using Microsoft.AspNet.Mvc.ApplicationModels.DefaultControllerModelBuilderTestControllers;
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Filters;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||
{
|
||||
public class DefaultControllerModelBuilderTest
|
||||
{
|
||||
[Fact]
|
||||
public void IsController_UserDefinedClass()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new AccessibleControllerModelBuilder();
|
||||
var typeInfo = typeof(StoreController).GetTypeInfo();
|
||||
|
||||
// Act
|
||||
var isController = builder.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.True(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_FrameworkControllerClass()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new AccessibleControllerModelBuilder();
|
||||
var typeInfo = typeof(Controller).GetTypeInfo();
|
||||
|
||||
// Act
|
||||
var isController = builder.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.False(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_UserDefinedControllerClass()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new AccessibleControllerModelBuilder();
|
||||
var typeInfo = typeof(DefaultControllerModelBuilderTestControllers.Controller).GetTypeInfo();
|
||||
|
||||
// Act
|
||||
var isController = builder.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.False(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_Interface()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new AccessibleControllerModelBuilder();
|
||||
var typeInfo = typeof(IController).GetTypeInfo();
|
||||
|
||||
// Act
|
||||
var isController = builder.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.False(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_AbstractClass()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new AccessibleControllerModelBuilder();
|
||||
var typeInfo = typeof(AbstractController).GetTypeInfo();
|
||||
|
||||
// Act
|
||||
var isController = builder.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.False(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_DerivedAbstractClass()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new AccessibleControllerModelBuilder();
|
||||
var typeInfo = typeof(DerivedAbstractController).GetTypeInfo();
|
||||
|
||||
// Act
|
||||
var isController = builder.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.True(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_OpenGenericClass()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new AccessibleControllerModelBuilder();
|
||||
var typeInfo = typeof(OpenGenericController<>).GetTypeInfo();
|
||||
|
||||
// Act
|
||||
var isController = builder.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.False(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_ClosedGenericClass()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new AccessibleControllerModelBuilder();
|
||||
var typeInfo = typeof(OpenGenericController<string>).GetTypeInfo();
|
||||
|
||||
// Act
|
||||
var isController = builder.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.True(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_DerivedGenericClass()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new AccessibleControllerModelBuilder();
|
||||
var typeInfo = typeof(DerivedGenericController).GetTypeInfo();
|
||||
|
||||
// Act
|
||||
var isController = builder.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.True(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_Poco_WithNamingConvention()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new AccessibleControllerModelBuilder();
|
||||
var typeInfo = typeof(PocoController).GetTypeInfo();
|
||||
|
||||
// Act
|
||||
var isController = builder.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.True(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_NoControllerSuffix()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new AccessibleControllerModelBuilder();
|
||||
var typeInfo = typeof(NoSuffix).GetTypeInfo();
|
||||
|
||||
// Act
|
||||
var isController = builder.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.True(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildControllerModel_DerivedFromControllerClass_HasFilter()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new AccessibleControllerModelBuilder();
|
||||
var builder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||
NullLoggerFactory.Instance);
|
||||
var typeInfo = typeof(StoreController).GetTypeInfo();
|
||||
|
||||
// Act
|
||||
|
|
@ -187,7 +33,8 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
public void BuildControllerModel_ClassWithoutFilterInterfaces_HasNoControllerFilter()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new AccessibleControllerModelBuilder();
|
||||
var builder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||
NullLoggerFactory.Instance);
|
||||
var typeInfo = typeof(NoFiltersController).GetTypeInfo();
|
||||
|
||||
// Act
|
||||
|
|
@ -202,7 +49,8 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
public void BuildControllerModel_ClassWithFilterInterfaces_HasFilter()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new AccessibleControllerModelBuilder();
|
||||
var builder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||
NullLoggerFactory.Instance);
|
||||
var typeInfo = typeof(SomeFiltersController).GetTypeInfo();
|
||||
|
||||
// Act
|
||||
|
|
@ -217,7 +65,8 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
public void BuildControllerModel_ClassWithFilterInterfaces_UnsupportedType()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new AccessibleControllerModelBuilder();
|
||||
var builder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||
NullLoggerFactory.Instance);
|
||||
var typeInfo = typeof(UnsupportedFiltersController).GetTypeInfo();
|
||||
|
||||
// Act
|
||||
|
|
@ -227,102 +76,49 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
Assert.Empty(model.Filters);
|
||||
}
|
||||
|
||||
private class AccessibleControllerModelBuilder : DefaultControllerModelBuilder
|
||||
private class StoreController : Mvc.Controller
|
||||
{
|
||||
public AccessibleControllerModelBuilder()
|
||||
: base(new DefaultActionModelBuilder(), new NullLoggerFactory())
|
||||
}
|
||||
|
||||
[Produces("application/json")]
|
||||
private class NoFiltersController
|
||||
{
|
||||
}
|
||||
|
||||
private class SomeFiltersController : IAsyncActionFilter, IResultFilter
|
||||
{
|
||||
public Task OnActionExecutionAsync(
|
||||
[NotNull] ActionExecutingContext context,
|
||||
[NotNull] ActionExecutionDelegate next)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void OnResultExecuted([NotNull] ResultExecutedContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public new bool IsController([NotNull]TypeInfo typeInfo)
|
||||
public void OnResultExecuting([NotNull]ResultExecutingContext context)
|
||||
{
|
||||
return base.IsController(typeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private class UnsupportedFiltersController : IExceptionFilter, IAuthorizationFilter, IAsyncResourceFilter
|
||||
{
|
||||
public void OnAuthorization([NotNull]AuthorizationContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnException([NotNull]ExceptionContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task OnResourceExecutionAsync([NotNull]ResourceExecutingContext context, [NotNull]ResourceExecutionDelegate next)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// These controllers are used to test the DefaultActionDiscoveryConventions 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.ApplicationModels.DefaultControllerModelBuilderTestControllers
|
||||
{
|
||||
public abstract class AbstractController : Mvc.Controller
|
||||
{
|
||||
}
|
||||
|
||||
public class DerivedAbstractController : AbstractController
|
||||
{
|
||||
}
|
||||
|
||||
public class StoreController : Mvc.Controller
|
||||
{
|
||||
}
|
||||
|
||||
public class Controller
|
||||
{
|
||||
}
|
||||
|
||||
public class OpenGenericController<T> : Mvc.Controller
|
||||
{
|
||||
}
|
||||
|
||||
public class DerivedGenericController : OpenGenericController<string>
|
||||
{
|
||||
}
|
||||
|
||||
public interface IController
|
||||
{
|
||||
}
|
||||
|
||||
public class NoSuffix : Mvc.Controller
|
||||
{
|
||||
}
|
||||
|
||||
public class PocoController
|
||||
{
|
||||
}
|
||||
|
||||
[Produces("application/json")]
|
||||
public class NoFiltersController
|
||||
{
|
||||
}
|
||||
|
||||
public class SomeFiltersController : IAsyncActionFilter, IResultFilter
|
||||
{
|
||||
public Task OnActionExecutionAsync(
|
||||
[NotNull] ActionExecutingContext context,
|
||||
[NotNull] ActionExecutionDelegate next)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void OnResultExecuted([NotNull] ResultExecutedContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnResultExecuting([NotNull ]ResultExecutingContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class UnsupportedFiltersController : IExceptionFilter, IAuthorizationFilter, IAsyncResourceFilter
|
||||
{
|
||||
public void OnAuthorization([NotNull]AuthorizationContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void OnException([NotNull]ExceptionContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task OnResourceExecutionAsync([NotNull]ResourceExecutingContext context, [NotNull]ResourceExecutionDelegate next)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1362,16 +1362,13 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
TypeInfo controllerTypeInfo,
|
||||
IEnumerable<IFilter> filters = null)
|
||||
{
|
||||
var modelBuilder = new StaticControllerModelBuilder(controllerTypeInfo);
|
||||
|
||||
var assemblyProvider = new Mock<IAssemblyProvider>();
|
||||
assemblyProvider
|
||||
.SetupGet(ap => ap.CandidateAssemblies)
|
||||
.Returns(new Assembly[] { controllerTypeInfo.Assembly });
|
||||
var controllerTypeProvider = new FixedSetControllerTypeProvider(new[] { controllerTypeInfo });
|
||||
var controllerModelBuilder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||
NullLoggerFactory.Instance);
|
||||
|
||||
var provider = new ControllerActionDescriptorProvider(
|
||||
assemblyProvider.Object,
|
||||
modelBuilder,
|
||||
controllerTypeProvider,
|
||||
controllerModelBuilder,
|
||||
new TestGlobalFilterProvider(filters),
|
||||
new MockMvcOptionsAccessor(),
|
||||
new NullLoggerFactory());
|
||||
|
|
@ -1382,16 +1379,13 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
private ControllerActionDescriptorProvider GetProvider(
|
||||
params TypeInfo[] controllerTypeInfo)
|
||||
{
|
||||
var modelBuilder = new StaticControllerModelBuilder(controllerTypeInfo);
|
||||
|
||||
var assemblyProvider = new Mock<IAssemblyProvider>();
|
||||
assemblyProvider
|
||||
.SetupGet(ap => ap.CandidateAssemblies)
|
||||
.Returns(new Assembly[] { controllerTypeInfo.First().Assembly });
|
||||
var controllerTypeProvider = new FixedSetControllerTypeProvider(controllerTypeInfo);
|
||||
var controllerModelBuilder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||
NullLoggerFactory.Instance);
|
||||
|
||||
var provider = new ControllerActionDescriptorProvider(
|
||||
assemblyProvider.Object,
|
||||
modelBuilder,
|
||||
controllerTypeProvider,
|
||||
controllerModelBuilder,
|
||||
new TestGlobalFilterProvider(),
|
||||
new MockMvcOptionsAccessor(),
|
||||
new NullLoggerFactory());
|
||||
|
|
@ -1403,18 +1397,15 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
TypeInfo type,
|
||||
IApplicationModelConvention convention)
|
||||
{
|
||||
var modelBuilder = new StaticControllerModelBuilder(type);
|
||||
|
||||
var assemblyProvider = new Mock<IAssemblyProvider>();
|
||||
assemblyProvider
|
||||
.SetupGet(ap => ap.CandidateAssemblies)
|
||||
.Returns(new Assembly[] { type.Assembly });
|
||||
var controllerTypeProvider = new FixedSetControllerTypeProvider(new[] { type });
|
||||
var modelBuilder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||
NullLoggerFactory.Instance);
|
||||
|
||||
var options = new MockMvcOptionsAccessor();
|
||||
options.Options.Conventions.Add(convention);
|
||||
|
||||
return new ControllerActionDescriptorProvider(
|
||||
assemblyProvider.Object,
|
||||
controllerTypeProvider,
|
||||
modelBuilder,
|
||||
new TestGlobalFilterProvider(),
|
||||
options,
|
||||
|
|
@ -1423,15 +1414,12 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
|
||||
private IEnumerable<ActionDescriptor> GetDescriptors(params TypeInfo[] controllerTypeInfos)
|
||||
{
|
||||
var modelBuilder = new StaticControllerModelBuilder(controllerTypeInfos);
|
||||
|
||||
var assemblyProvider = new Mock<IAssemblyProvider>();
|
||||
assemblyProvider
|
||||
.SetupGet(ap => ap.CandidateAssemblies)
|
||||
.Returns(controllerTypeInfos.Select(cti => cti.Assembly).Distinct());
|
||||
var controllerTypeProvider = new FixedSetControllerTypeProvider(controllerTypeInfos);
|
||||
var modelBuilder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||
NullLoggerFactory.Instance);
|
||||
|
||||
var provider = new ControllerActionDescriptorProvider(
|
||||
assemblyProvider.Object,
|
||||
controllerTypeProvider,
|
||||
modelBuilder,
|
||||
new TestGlobalFilterProvider(),
|
||||
new MockMvcOptionsAccessor(),
|
||||
|
|
|
|||
|
|
@ -8,32 +8,12 @@ using Microsoft.AspNet.Mvc.ApplicationModels;
|
|||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.DependencyInjection.NestedProviders;
|
||||
using Microsoft.Framework.Logging;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Logging
|
||||
{
|
||||
public class DefaultActionDescriptorCollectionProviderLoggingTest
|
||||
{
|
||||
[Fact]
|
||||
public void SimpleController_AssemblyDiscovery()
|
||||
{
|
||||
// Arrange
|
||||
var sink = new TestSink();
|
||||
var loggerFactory = new TestLoggerFactory(sink);
|
||||
|
||||
// Act
|
||||
var provider = GetProvider(loggerFactory, typeof(SimpleController).GetTypeInfo());
|
||||
provider.BuildModel();
|
||||
|
||||
// Assert
|
||||
Assert.Single(sink.Writes);
|
||||
|
||||
var assemblyValues = sink.Writes[0].State as AssemblyValues;
|
||||
Assert.NotNull(assemblyValues);
|
||||
Assert.True(assemblyValues.AssemblyName.Contains("Microsoft.AspNet.Mvc.Core.Test"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ControllerDiscovery()
|
||||
{
|
||||
|
|
@ -49,10 +29,10 @@ namespace Microsoft.AspNet.Mvc.Logging
|
|||
provider.GetDescriptors();
|
||||
|
||||
// Assert
|
||||
// 1 assembly, 2 controllers
|
||||
Assert.Equal(3, sink.Writes.Count);
|
||||
// 2 controllers
|
||||
Assert.Equal(2, sink.Writes.Count);
|
||||
|
||||
var controllerModelValues = sink.Writes[1].State as ControllerModelValues;
|
||||
var controllerModelValues = Assert.IsType<ControllerModelValues>(sink.Writes[0].State);
|
||||
Assert.NotNull(controllerModelValues);
|
||||
Assert.Equal("Simple", controllerModelValues.ControllerName);
|
||||
Assert.Equal(typeof(SimpleController), controllerModelValues.ControllerType);
|
||||
|
|
@ -62,7 +42,7 @@ namespace Microsoft.AspNet.Mvc.Logging
|
|||
Assert.Empty(controllerModelValues.Attributes);
|
||||
Assert.Empty(controllerModelValues.Filters);
|
||||
|
||||
controllerModelValues = sink.Writes[2].State as ControllerModelValues;
|
||||
controllerModelValues = Assert.IsType<ControllerModelValues>(sink.Writes[1].State);
|
||||
Assert.NotNull(controllerModelValues);
|
||||
Assert.Equal("Basic", controllerModelValues.ControllerName);
|
||||
Assert.Equal(typeof(BasicController), controllerModelValues.ControllerType);
|
||||
|
|
@ -88,10 +68,12 @@ namespace Microsoft.AspNet.Mvc.Logging
|
|||
typeof(BasicController).GetTypeInfo());
|
||||
|
||||
// Assert
|
||||
// 1 assembly, 2 controllers, 3 actions
|
||||
Assert.Equal(6, sink.Writes.Count);
|
||||
// 2 controllers, 3 actions
|
||||
Assert.Equal(5, sink.Writes.Count);
|
||||
Assert.IsType<ControllerModelValues>(sink.Writes[0].State);
|
||||
Assert.IsType<ControllerModelValues>(sink.Writes[1].State);
|
||||
|
||||
var actionDescriptorValues = sink.Writes[3].State as ActionDescriptorValues;
|
||||
var actionDescriptorValues = Assert.IsType<ActionDescriptorValues>(sink.Writes[2].State);
|
||||
Assert.NotNull(actionDescriptorValues);
|
||||
Assert.Equal("EmptyAction", actionDescriptorValues.Name);
|
||||
Assert.Equal("Simple", actionDescriptorValues.ControllerName);
|
||||
|
|
@ -101,7 +83,7 @@ namespace Microsoft.AspNet.Mvc.Logging
|
|||
Assert.Empty(actionDescriptorValues.FilterDescriptors);
|
||||
Assert.Empty(actionDescriptorValues.Parameters);
|
||||
|
||||
actionDescriptorValues = sink.Writes[4].State as ActionDescriptorValues;
|
||||
actionDescriptorValues = Assert.IsType<ActionDescriptorValues>(sink.Writes[3].State);
|
||||
Assert.NotNull(actionDescriptorValues);
|
||||
Assert.Equal("Basic", actionDescriptorValues.Name);
|
||||
Assert.Equal("Basic", actionDescriptorValues.ControllerName);
|
||||
|
|
@ -111,7 +93,7 @@ namespace Microsoft.AspNet.Mvc.Logging
|
|||
Assert.Equal(2, actionDescriptorValues.FilterDescriptors.Count);
|
||||
Assert.Empty(actionDescriptorValues.Parameters);
|
||||
|
||||
actionDescriptorValues = sink.Writes[5].State as ActionDescriptorValues;
|
||||
actionDescriptorValues = Assert.IsType<ActionDescriptorValues>(sink.Writes[4].State);
|
||||
Assert.NotNull(actionDescriptorValues);
|
||||
Assert.Equal("Basic", actionDescriptorValues.Name);
|
||||
Assert.Equal("Basic", actionDescriptorValues.ControllerName);
|
||||
|
|
@ -140,15 +122,12 @@ namespace Microsoft.AspNet.Mvc.Logging
|
|||
private ControllerActionDescriptorProvider GetProvider(
|
||||
ILoggerFactory loggerFactory, params TypeInfo[] controllerTypeInfo)
|
||||
{
|
||||
var modelBuilder = new StaticControllerModelBuilder(controllerTypeInfo);
|
||||
|
||||
var assemblyProvider = new Mock<IAssemblyProvider>();
|
||||
assemblyProvider
|
||||
.SetupGet(ap => ap.CandidateAssemblies)
|
||||
.Returns(new Assembly[] { controllerTypeInfo.First().Assembly });
|
||||
var controllerTypeProvider = new FixedSetControllerTypeProvider(controllerTypeInfo);
|
||||
var modelBuilder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||
loggerFactory);
|
||||
|
||||
var provider = new ControllerActionDescriptorProvider(
|
||||
assemblyProvider.Object,
|
||||
controllerTypeProvider,
|
||||
modelBuilder,
|
||||
new TestGlobalFilterProvider(),
|
||||
new MockMvcOptionsAccessor(),
|
||||
|
|
|
|||
|
|
@ -759,16 +759,17 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
private ControllerActionDescriptorProvider GetActionDescriptorProvider()
|
||||
{
|
||||
var assemblyProvider = new StaticAssemblyProvider();
|
||||
|
||||
var controllerTypes = typeof(DefaultActionSelectorTests)
|
||||
.GetNestedTypes(BindingFlags.NonPublic)
|
||||
.Select(t => t.GetTypeInfo());
|
||||
.Select(t => t.GetTypeInfo())
|
||||
.ToList();
|
||||
|
||||
var modelBuilder = new StaticControllerModelBuilder(controllerTypes.ToArray());
|
||||
var controllerTypeProvider = new FixedSetControllerTypeProvider(controllerTypes);
|
||||
var modelBuilder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||
NullLoggerFactory.Instance);
|
||||
|
||||
return new ControllerActionDescriptorProvider(
|
||||
assemblyProvider,
|
||||
controllerTypeProvider,
|
||||
modelBuilder,
|
||||
new TestGlobalFilterProvider(),
|
||||
new MockMvcOptionsAccessor(),
|
||||
|
|
|
|||
|
|
@ -1,182 +1,79 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
#if ASPNET50
|
||||
using System;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Core.Test
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class DefaultControllerActivatorTest
|
||||
{
|
||||
[Fact]
|
||||
public void Activate_SetsPropertiesFromActionContextHierarchy()
|
||||
[Theory]
|
||||
[InlineData(typeof(TypeDerivingFromController))]
|
||||
[InlineData(typeof(PocoType))]
|
||||
public void Create_CreatesInstancesOfTypes(Type type)
|
||||
{
|
||||
// Arrange
|
||||
var services = GetServices();
|
||||
|
||||
var httpRequest = Mock.Of<HttpRequest>();
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
httpContext.SetupGet(c => c.Request)
|
||||
.Returns(httpRequest);
|
||||
httpContext.SetupGet(c => c.RequestServices)
|
||||
.Returns(services);
|
||||
|
||||
var controller = new TestController();
|
||||
var context = new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
|
||||
var activator = new DefaultControllerActivator();
|
||||
|
||||
var actionContext = new ActionContext(new DefaultHttpContext(),
|
||||
new RouteData(),
|
||||
new ActionDescriptor());
|
||||
// Act
|
||||
activator.Activate(controller, context);
|
||||
var instance = activator.Create(actionContext, type);
|
||||
|
||||
// Assert
|
||||
Assert.Same(context, controller.ActionContext);
|
||||
Assert.Same(httpContext.Object, controller.HttpContext);
|
||||
Assert.Same(httpRequest, controller.GetHttpRequest());
|
||||
Assert.IsType(type, instance);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Activate_SetsViewDatDictionary()
|
||||
public void Create_TypeActivatesTypesWithServices()
|
||||
{
|
||||
// Arrange
|
||||
var services = GetServices();
|
||||
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
httpContext.SetupGet(c => c.RequestServices)
|
||||
.Returns(services);
|
||||
|
||||
var controller = new TestController();
|
||||
var context = new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
|
||||
var activator = new DefaultControllerActivator();
|
||||
|
||||
// Act
|
||||
activator.Activate(controller, context);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(controller.GetViewData());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Activate_SetsBindingContext()
|
||||
{
|
||||
// Arrange
|
||||
var bindingContext = new ActionBindingContext();
|
||||
|
||||
var services = GetServices();
|
||||
services.GetRequiredService<IScopedInstance<ActionBindingContext>>().Value = bindingContext;
|
||||
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
httpContext.SetupGet(c => c.RequestServices)
|
||||
.Returns(services);
|
||||
|
||||
var controller = new TestController();
|
||||
var context = new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
|
||||
|
||||
var activator = new DefaultControllerActivator();
|
||||
|
||||
// Act
|
||||
activator.Activate(controller, context);
|
||||
|
||||
// Assert
|
||||
Assert.Same(bindingContext, controller.BindingContext);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Activate_PopulatesServicesFromServiceContainer()
|
||||
{
|
||||
// Arrange
|
||||
var services = GetServices();
|
||||
var urlHelper = services.GetRequiredService<IUrlHelper>();
|
||||
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
httpContext.SetupGet(c => c.RequestServices)
|
||||
.Returns(services);
|
||||
|
||||
var controller = new TestController();
|
||||
var context = new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
|
||||
var activator = new DefaultControllerActivator();
|
||||
|
||||
// Act
|
||||
activator.Activate(controller, context);
|
||||
|
||||
// Assert
|
||||
Assert.Same(urlHelper, controller.Helper);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Activate_IgnoresPropertiesThatAreNotDecoratedWithActivateAttribute()
|
||||
{
|
||||
// Arrange
|
||||
var services = GetServices();
|
||||
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
httpContext.SetupGet(c => c.Response)
|
||||
.Returns(Mock.Of<HttpResponse>());
|
||||
httpContext.SetupGet(c => c.RequestServices)
|
||||
.Returns(services);
|
||||
|
||||
var controller = new TestController();
|
||||
var context = new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
|
||||
var activator = new DefaultControllerActivator();
|
||||
|
||||
// Act
|
||||
activator.Activate(controller, context);
|
||||
|
||||
// Assert
|
||||
Assert.Null(controller.Response);
|
||||
}
|
||||
|
||||
private IServiceProvider GetServices()
|
||||
{
|
||||
var services = new Mock<IServiceProvider>();
|
||||
services.Setup(s => s.GetService(typeof(IUrlHelper)))
|
||||
.Returns(Mock.Of<IUrlHelper>());
|
||||
services.Setup(s => s.GetService(typeof(IModelMetadataProvider)))
|
||||
.Returns(new EmptyModelMetadataProvider());
|
||||
services
|
||||
.Setup(s => s.GetService(typeof(IScopedInstance<ActionBindingContext>)))
|
||||
.Returns(new MockScopedInstance<ActionBindingContext>());
|
||||
return services.Object;
|
||||
}
|
||||
|
||||
public class TestController
|
||||
{
|
||||
[Activate]
|
||||
public ActionContext ActionContext { get; set; }
|
||||
|
||||
[Activate]
|
||||
public ActionBindingContext BindingContext { get; set; }
|
||||
|
||||
[Activate]
|
||||
public HttpContext HttpContext { get; set; }
|
||||
|
||||
[Activate]
|
||||
protected HttpRequest Request { get; set; }
|
||||
|
||||
[Activate]
|
||||
private ViewDataDictionary ViewData { get; set; }
|
||||
|
||||
[Activate]
|
||||
public IUrlHelper Helper { get; set; }
|
||||
|
||||
public HttpResponse Response { get; set; }
|
||||
|
||||
public ViewDataDictionary GetViewData()
|
||||
var serviceProvider = new Mock<IServiceProvider>(MockBehavior.Strict);
|
||||
var testService = new TestService();
|
||||
serviceProvider.Setup(s => s.GetService(typeof(TestService)))
|
||||
.Returns(testService)
|
||||
.Verifiable();
|
||||
var httpContext = new DefaultHttpContext
|
||||
{
|
||||
return ViewData;
|
||||
RequestServices = serviceProvider.Object
|
||||
};
|
||||
var actionContext = new ActionContext(httpContext,
|
||||
new RouteData(),
|
||||
new ActionDescriptor());
|
||||
// Act
|
||||
var instance = activator.Create(actionContext, typeof(TypeDerivingFromControllerWithServices));
|
||||
|
||||
// Assert
|
||||
var controller = Assert.IsType<TypeDerivingFromControllerWithServices>(instance);
|
||||
Assert.Same(testService, controller.TestService);
|
||||
serviceProvider.Verify();
|
||||
}
|
||||
|
||||
private class TypeDerivingFromController : Controller
|
||||
{
|
||||
}
|
||||
|
||||
private class TypeDerivingFromControllerWithServices : Controller
|
||||
{
|
||||
public TypeDerivingFromControllerWithServices(TestService service)
|
||||
{
|
||||
TestService = service;
|
||||
}
|
||||
|
||||
public HttpRequest GetHttpRequest()
|
||||
{
|
||||
return Request;
|
||||
}
|
||||
public TestService TestService { get; }
|
||||
}
|
||||
|
||||
private class PocoType
|
||||
{
|
||||
}
|
||||
|
||||
private class TestService
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2,23 +2,249 @@
|
|||
// 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.Http;
|
||||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Core.Test
|
||||
namespace Microsoft.AspNet.Mvc.Core
|
||||
{
|
||||
public class DefaultControllerFactoryTest
|
||||
{
|
||||
[Fact]
|
||||
public void CreateController_ThrowsIfActionDescriptorIsNotControllerActionDescriptor()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "The action descriptor must be of type 'Microsoft.AspNet.Mvc.ControllerActionDescriptor'." +
|
||||
Environment.NewLine + "Parameter name: actionContext";
|
||||
var actionDescriptor = new ActionDescriptor();
|
||||
var controllerFactory = new DefaultControllerFactory(Mock.Of<IControllerActivator>());
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var actionContext = new ActionContext(httpContext,
|
||||
new RouteData(),
|
||||
actionDescriptor);
|
||||
|
||||
// Act and Assert
|
||||
var ex = Assert.Throws<ArgumentException>(() =>
|
||||
controllerFactory.CreateController(actionContext));
|
||||
Assert.Equal(expected, ex.Message);
|
||||
Assert.Equal("actionContext", ex.ParamName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateController_UsesControllerActivatorToInstantiateController()
|
||||
{
|
||||
// Arrange
|
||||
var expected = new MyController();
|
||||
var actionDescriptor = new ControllerActionDescriptor
|
||||
{
|
||||
ControllerTypeInfo = typeof(MyController).GetTypeInfo()
|
||||
};
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.RequestServices = GetServices();
|
||||
var actionContext = new ActionContext(httpContext,
|
||||
new RouteData(),
|
||||
actionDescriptor);
|
||||
var activator = new Mock<IControllerActivator>();
|
||||
activator.Setup(a => a.Create(actionContext, typeof(MyController)))
|
||||
.Returns(expected)
|
||||
.Verifiable();
|
||||
|
||||
var controllerFactory = new DefaultControllerFactory(activator.Object);
|
||||
|
||||
// Act
|
||||
var result = controllerFactory.CreateController(actionContext);
|
||||
|
||||
// Assert
|
||||
var controller = Assert.IsType<MyController>(result);
|
||||
Assert.Same(expected, controller);
|
||||
activator.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateController_SetsPropertiesFromActionContextHierarchy()
|
||||
{
|
||||
// Arrange
|
||||
var actionDescriptor = new ControllerActionDescriptor
|
||||
{
|
||||
ControllerTypeInfo = typeof(ControllerWithActivateAndFromServices).GetTypeInfo()
|
||||
};
|
||||
var services = GetServices();
|
||||
var httpContext = new DefaultHttpContext
|
||||
{
|
||||
RequestServices = services
|
||||
};
|
||||
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
|
||||
var factory = new DefaultControllerFactory(new DefaultControllerActivator());
|
||||
|
||||
// Act
|
||||
var result = factory.CreateController(context);
|
||||
|
||||
// Assert
|
||||
var controller = Assert.IsType<ControllerWithActivateAndFromServices>(result);
|
||||
Assert.Same(context, controller.ActionContext);
|
||||
Assert.Same(httpContext, controller.HttpContext);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateController_SetsViewDataDictionary()
|
||||
{
|
||||
// Arrange
|
||||
var actionDescriptor = new ControllerActionDescriptor
|
||||
{
|
||||
ControllerTypeInfo = typeof(ControllerWithActivateAndFromServices).GetTypeInfo()
|
||||
};
|
||||
|
||||
var services = GetServices();
|
||||
var httpContext = new DefaultHttpContext
|
||||
{
|
||||
RequestServices = services
|
||||
};
|
||||
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
|
||||
var factory = new DefaultControllerFactory(new DefaultControllerActivator());
|
||||
|
||||
// Act
|
||||
var result = factory.CreateController(context);
|
||||
|
||||
// Assert
|
||||
var controller = Assert.IsType<ControllerWithActivateAndFromServices>(result);
|
||||
Assert.NotNull(controller.GetViewData());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateController_SetsBindingContext()
|
||||
{
|
||||
// Arrange
|
||||
var actionDescriptor = new ControllerActionDescriptor
|
||||
{
|
||||
ControllerTypeInfo = typeof(ControllerWithActivateAndFromServices).GetTypeInfo()
|
||||
};
|
||||
var bindingContext = new ActionBindingContext();
|
||||
|
||||
var services = GetServices();
|
||||
services.GetRequiredService<IScopedInstance<ActionBindingContext>>().Value = bindingContext;
|
||||
var httpContext = new DefaultHttpContext
|
||||
{
|
||||
RequestServices = services
|
||||
};
|
||||
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
|
||||
var factory = new DefaultControllerFactory(new DefaultControllerActivator());
|
||||
|
||||
// Act
|
||||
var result = factory.CreateController(context);
|
||||
|
||||
// Assert
|
||||
var controller = Assert.IsType<ControllerWithActivateAndFromServices>(result);
|
||||
Assert.Same(bindingContext, controller.BindingContext);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateController_PopulatesServicesFromServiceContainer()
|
||||
{
|
||||
// Arrange
|
||||
var actionDescriptor = new ControllerActionDescriptor
|
||||
{
|
||||
ControllerTypeInfo = typeof(ControllerWithActivateAndFromServices).GetTypeInfo()
|
||||
};
|
||||
var services = GetServices();
|
||||
var urlHelper = services.GetRequiredService<IUrlHelper>();
|
||||
|
||||
var httpContext = new DefaultHttpContext
|
||||
{
|
||||
RequestServices = services
|
||||
};
|
||||
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
|
||||
var factory = new DefaultControllerFactory(new DefaultControllerActivator());
|
||||
|
||||
// Act
|
||||
var result = factory.CreateController(context);
|
||||
|
||||
// Assert
|
||||
var controller = Assert.IsType<ControllerWithActivateAndFromServices>(result);
|
||||
Assert.Same(urlHelper, controller.Helper);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateController_PopulatesUserServicesFromServiceContainer()
|
||||
{
|
||||
// Arrange
|
||||
var actionDescriptor = new ControllerActionDescriptor
|
||||
{
|
||||
ControllerTypeInfo = typeof(ControllerWithActivateAndFromServices).GetTypeInfo()
|
||||
};
|
||||
var services = GetServices();
|
||||
var testService = services.GetService<TestService>();
|
||||
|
||||
var httpContext = new DefaultHttpContext
|
||||
{
|
||||
RequestServices = services
|
||||
};
|
||||
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
|
||||
var factory = new DefaultControllerFactory(new DefaultControllerActivator());
|
||||
|
||||
// Act
|
||||
var result = factory.CreateController(context);
|
||||
|
||||
// Assert
|
||||
var controller = Assert.IsType<ControllerWithActivateAndFromServices>(result);
|
||||
Assert.Same(testService, controller.TestService);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateController_IgnoresPropertiesThatAreNotDecoratedWithActivateAttribute()
|
||||
{
|
||||
// Arrange
|
||||
var actionDescriptor = new ControllerActionDescriptor
|
||||
{
|
||||
ControllerTypeInfo = typeof(ControllerWithActivateAndFromServices).GetTypeInfo()
|
||||
};
|
||||
var services = GetServices();
|
||||
var httpContext = new DefaultHttpContext
|
||||
{
|
||||
RequestServices = services
|
||||
};
|
||||
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
|
||||
var factory = new DefaultControllerFactory(new DefaultControllerActivator());
|
||||
|
||||
// Act
|
||||
var result = factory.CreateController(context);
|
||||
|
||||
// Assert
|
||||
var controller = Assert.IsType<ControllerWithActivateAndFromServices>(result);
|
||||
Assert.Null(controller.Response);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateController_ThrowsIfPropertyCannotBeActivated()
|
||||
{
|
||||
// Arrange
|
||||
var actionDescriptor = new ControllerActionDescriptor
|
||||
{
|
||||
ControllerTypeInfo = typeof(ControllerThatCannotBeActivated).GetTypeInfo()
|
||||
};
|
||||
var services = GetServices();
|
||||
var httpContext = new DefaultHttpContext
|
||||
{
|
||||
RequestServices = services
|
||||
};
|
||||
var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
|
||||
var factory = new DefaultControllerFactory(new DefaultControllerActivator());
|
||||
|
||||
// Act and Assert
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => factory.CreateController(context));
|
||||
Assert.Equal("The property 'Service' on controller '" + typeof(ControllerThatCannotBeActivated) +
|
||||
"' cannot be activated.", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DefaultControllerFactory_DisposesIDisposableController()
|
||||
{
|
||||
// Arrange
|
||||
var factory = new DefaultControllerFactory(
|
||||
Mock.Of<IServiceProvider>(),
|
||||
Mock.Of<ITypeActivator>(),
|
||||
Mock.Of<IControllerActivator>());
|
||||
|
||||
var factory = new DefaultControllerFactory(Mock.Of<IControllerActivator>());
|
||||
var controller = new MyController();
|
||||
|
||||
// Act + Assert
|
||||
|
|
@ -33,17 +259,64 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
public void DefaultControllerFactory_ReleasesNonIDisposableController()
|
||||
{
|
||||
// Arrange
|
||||
var factory = new DefaultControllerFactory(
|
||||
Mock.Of<IServiceProvider>(),
|
||||
Mock.Of<ITypeActivator>(),
|
||||
Mock.Of<IControllerActivator>());
|
||||
|
||||
var controller = new Object();
|
||||
var factory = new DefaultControllerFactory(Mock.Of<IControllerActivator>());
|
||||
var controller = new object();
|
||||
|
||||
// Act + Assert (does not throw)
|
||||
factory.ReleaseController(controller);
|
||||
}
|
||||
|
||||
private IServiceProvider GetServices()
|
||||
{
|
||||
var services = new Mock<IServiceProvider>();
|
||||
services.Setup(s => s.GetService(typeof(IUrlHelper)))
|
||||
.Returns(Mock.Of<IUrlHelper>());
|
||||
services.Setup(s => s.GetService(typeof(IModelMetadataProvider)))
|
||||
.Returns(new EmptyModelMetadataProvider());
|
||||
services.Setup(s => s.GetService(typeof(TestService)))
|
||||
.Returns(new TestService());
|
||||
services
|
||||
.Setup(s => s.GetService(typeof(IScopedInstance<ActionBindingContext>)))
|
||||
.Returns(new MockScopedInstance<ActionBindingContext>());
|
||||
return services.Object;
|
||||
}
|
||||
|
||||
private class ControllerWithActivateAndFromServices
|
||||
{
|
||||
[Activate]
|
||||
public ActionContext ActionContext { get; set; }
|
||||
|
||||
[Activate]
|
||||
public ActionBindingContext BindingContext { get; set; }
|
||||
|
||||
[Activate]
|
||||
public HttpContext HttpContext { get; set; }
|
||||
|
||||
[Activate]
|
||||
protected HttpRequest Request { get; set; }
|
||||
|
||||
[Activate]
|
||||
private ViewDataDictionary ViewData { get; set; }
|
||||
|
||||
[FromServices]
|
||||
public IUrlHelper Helper { get; set; }
|
||||
|
||||
[FromServices]
|
||||
public TestService TestService { get; set; }
|
||||
|
||||
public HttpResponse Response { get; set; }
|
||||
|
||||
public ViewDataDictionary GetViewData()
|
||||
{
|
||||
return ViewData;
|
||||
}
|
||||
|
||||
public HttpRequest GetHttpRequest()
|
||||
{
|
||||
return Request;
|
||||
}
|
||||
}
|
||||
|
||||
private class MyController : Controller
|
||||
{
|
||||
public bool Disposed { get; set; }
|
||||
|
|
@ -53,5 +326,16 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
Disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private class ControllerThatCannotBeActivated
|
||||
{
|
||||
[Activate]
|
||||
public TestService Service { get; set; }
|
||||
}
|
||||
|
||||
private class TestService
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,217 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.DefaultControllerTypeProviderControllers;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class DefaultControllerTypeProviderTest
|
||||
{
|
||||
[Fact]
|
||||
public void IsController_UserDefinedClass()
|
||||
{
|
||||
// Arrange
|
||||
var typeInfo = typeof(StoreController).GetTypeInfo();
|
||||
var provider = GetControllerTypeProvider();
|
||||
|
||||
// Act
|
||||
var isController = provider.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.True(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_FrameworkControllerClass()
|
||||
{
|
||||
// Arrange
|
||||
var typeInfo = typeof(Controller).GetTypeInfo();
|
||||
var provider = GetControllerTypeProvider();
|
||||
|
||||
// Act
|
||||
var isController = provider.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.False(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_UserDefinedControllerClass()
|
||||
{
|
||||
// Arrange
|
||||
var typeInfo = typeof(DefaultControllerTypeProviderControllers.Controller).GetTypeInfo();
|
||||
var provider = GetControllerTypeProvider();
|
||||
|
||||
// Act
|
||||
var isController = provider.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.False(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_Interface()
|
||||
{
|
||||
// Arrange
|
||||
var typeInfo = typeof(IController).GetTypeInfo();
|
||||
var provider = GetControllerTypeProvider();
|
||||
|
||||
// Act
|
||||
var isController = provider.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.False(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_AbstractClass()
|
||||
{
|
||||
// Arrange
|
||||
var typeInfo = typeof(AbstractController).GetTypeInfo();
|
||||
var provider = GetControllerTypeProvider();
|
||||
|
||||
// Act
|
||||
var isController = provider.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.False(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_DerivedAbstractClass()
|
||||
{
|
||||
// Arrange
|
||||
var typeInfo = typeof(DerivedAbstractController).GetTypeInfo();
|
||||
var provider = GetControllerTypeProvider();
|
||||
|
||||
// Act
|
||||
var isController = provider.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.True(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_OpenGenericClass()
|
||||
{
|
||||
// Arrange
|
||||
var typeInfo = typeof(OpenGenericController<>).GetTypeInfo();
|
||||
var provider = GetControllerTypeProvider();
|
||||
|
||||
// Act
|
||||
var isController = provider.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.False(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_ClosedGenericClass()
|
||||
{
|
||||
// Arrange
|
||||
var typeInfo = typeof(OpenGenericController<string>).GetTypeInfo();
|
||||
var provider = GetControllerTypeProvider();
|
||||
|
||||
// Act
|
||||
var isController = provider.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.True(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_DerivedGenericClass()
|
||||
{
|
||||
// Arrange
|
||||
var typeInfo = typeof(DerivedGenericController).GetTypeInfo();
|
||||
var provider = GetControllerTypeProvider();
|
||||
|
||||
// Act
|
||||
var isController = provider.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.True(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_Poco_WithNamingConvention()
|
||||
{
|
||||
// Arrange
|
||||
var typeInfo = typeof(PocoController).GetTypeInfo();
|
||||
var provider = GetControllerTypeProvider();
|
||||
|
||||
// Act
|
||||
var isController = provider.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.True(isController);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsController_NoControllerSuffix()
|
||||
{
|
||||
// Arrange
|
||||
var typeInfo = typeof(NoSuffix).GetTypeInfo();
|
||||
var provider = GetControllerTypeProvider();
|
||||
|
||||
// Act
|
||||
var isController = provider.IsController(typeInfo);
|
||||
|
||||
// Assert
|
||||
Assert.True(isController);
|
||||
}
|
||||
|
||||
private static DefaultControllerTypeProvider GetControllerTypeProvider()
|
||||
{
|
||||
var assemblyProvider = new FixedSetAssemblyProvider();
|
||||
return new DefaultControllerTypeProvider(assemblyProvider, NullLoggerFactory.Instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// These controllers are used to test the DefaultControllerTypeProvider 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.DefaultControllerTypeProviderControllers
|
||||
{
|
||||
public abstract class AbstractController : Mvc.Controller
|
||||
{
|
||||
}
|
||||
|
||||
public class DerivedAbstractController : AbstractController
|
||||
{
|
||||
}
|
||||
|
||||
public class StoreController : Mvc.Controller
|
||||
{
|
||||
}
|
||||
|
||||
public class Controller
|
||||
{
|
||||
}
|
||||
|
||||
public class OpenGenericController<T> : Mvc.Controller
|
||||
{
|
||||
}
|
||||
|
||||
public class DerivedGenericController : OpenGenericController<string>
|
||||
{
|
||||
}
|
||||
|
||||
public interface IController
|
||||
{
|
||||
}
|
||||
|
||||
public class NoSuffix : Mvc.Controller
|
||||
{
|
||||
}
|
||||
|
||||
public class PocoController
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.Http.Core;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class ServiceBasedControllerActivatorTest
|
||||
{
|
||||
[Fact]
|
||||
public void Create_GetsServicesFromServiceProvider()
|
||||
{
|
||||
// Arrange
|
||||
var controller = new DIController();
|
||||
var serviceProvider = new Mock<IServiceProvider>(MockBehavior.Strict);
|
||||
serviceProvider.Setup(s => s.GetService(typeof(DIController)))
|
||||
.Returns(controller)
|
||||
.Verifiable();
|
||||
var httpContext = new DefaultHttpContext
|
||||
{
|
||||
RequestServices = serviceProvider.Object
|
||||
};
|
||||
var activator = new ServiceBasedControllerActivator();
|
||||
var actionContext = new ActionContext(httpContext,
|
||||
new RouteData(),
|
||||
new ActionDescriptor());
|
||||
|
||||
// Act
|
||||
var instance = activator.Create(actionContext, typeof(DIController));
|
||||
|
||||
// Assert
|
||||
Assert.Same(controller, instance);
|
||||
serviceProvider.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_ThrowsIfControllerIsNotRegisteredInServiceProvider()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "No service for type '" + typeof(DIController) + "' has been registered.";
|
||||
var controller = new DIController();
|
||||
var serviceProvider = new Mock<IServiceProvider>();
|
||||
var httpContext = new DefaultHttpContext
|
||||
{
|
||||
RequestServices = serviceProvider.Object
|
||||
};
|
||||
var activator = new ServiceBasedControllerActivator();
|
||||
var actionContext = new ActionContext(httpContext,
|
||||
new RouteData(),
|
||||
new ActionDescriptor());
|
||||
|
||||
// Act and Assert
|
||||
var ex = Assert.Throws<InvalidOperationException>(
|
||||
() => activator.Create(actionContext, typeof(DIController)));
|
||||
Assert.Equal(expected, ex.Message);
|
||||
}
|
||||
|
||||
private class DIController : Controller
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// An implementation of IAssemblyProvider that provides just this assembly.
|
||||
/// </summary>
|
||||
public class StaticAssemblyProvider : IAssemblyProvider
|
||||
{
|
||||
public IEnumerable<Assembly> CandidateAssemblies
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return typeof(StaticAssemblyProvider).GetTypeInfo().Assembly;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||
{
|
||||
/// <summary>
|
||||
/// An implementation of StaticControllerModelBuilder that only allows controllers
|
||||
/// from a fixed set of types.
|
||||
/// </summary>
|
||||
public class StaticControllerModelBuilder : DefaultControllerModelBuilder
|
||||
{
|
||||
public StaticControllerModelBuilder(params TypeInfo[] controllerTypes)
|
||||
: base(new DefaultActionModelBuilder(), new NullLoggerFactory())
|
||||
{
|
||||
ControllerTypes = new List<TypeInfo>(controllerTypes ?? Enumerable.Empty<TypeInfo>());
|
||||
}
|
||||
|
||||
public List<TypeInfo> ControllerTypes { get; private set; }
|
||||
|
||||
protected override bool IsController([NotNull] TypeInfo typeInfo)
|
||||
{
|
||||
return ControllerTypes.Contains(typeInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -177,7 +177,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
private class FilteredViewComponentSelector : DefaultViewComponentSelector
|
||||
{
|
||||
public FilteredViewComponentSelector()
|
||||
: base(new StaticAssemblyProvider())
|
||||
: base(GetAssemblyProvider())
|
||||
{
|
||||
AllowedTypes = typeof(DefaultViewComponentSelectorTest).GetNestedTypes(BindingFlags.NonPublic);
|
||||
}
|
||||
|
|
@ -188,6 +188,15 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
return AllowedTypes.Contains(typeInfo.AsType());
|
||||
}
|
||||
|
||||
private static IAssemblyProvider GetAssemblyProvider()
|
||||
{
|
||||
var assemblyProvider = new FixedSetAssemblyProvider();
|
||||
assemblyProvider.CandidateAssemblies.Add(
|
||||
typeof(FilteredViewComponentSelector).GetTypeInfo().Assembly);
|
||||
|
||||
return assemblyProvider;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,8 +22,8 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var expectedMessage = "No service for type 'ActivatorWebSite.CannotBeActivatedController+FakeType' " +
|
||||
"has been registered.";
|
||||
var expectedMessage = "The property 'Service' on controller 'ActivatorWebSite.CannotBeActivatedController' " +
|
||||
"cannot be activated.";
|
||||
|
||||
// Act & Assert
|
||||
var response = await client.GetAsync("http://localhost/CannotBeActivated/Index");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using ControllersFromServicesWebSite;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||
{
|
||||
public class ControllerFromServicesTest
|
||||
{
|
||||
private readonly IServiceProvider _provider = TestHelper.CreateServices(
|
||||
nameof(ControllersFromServicesWebSite));
|
||||
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
|
||||
|
||||
[Fact]
|
||||
public async Task ControllersWithConstructorInjectionAreCreatedAndActivated()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "/constructorinjection 14 test-header-value";
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("Test-Header", "test-header-value");
|
||||
|
||||
// Act
|
||||
var response = await client.GetStringAsync("http://localhost/constructorinjection?value=14");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, response);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TypesDerivingFromControllerAreRegistered()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "No schedules available for 23";
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetStringAsync("http://localhost/schedule/23");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, response);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TypesWithControllerSuffixAreRegistered()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "Updated record employee303";
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.PutAsync("http://localhost/employee/update_records?recordId=employee303",
|
||||
new StringContent(string.Empty));
|
||||
|
||||
// Assert
|
||||
response.EnsureSuccessStatusCode();
|
||||
Assert.Equal(expected, await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TypesWithControllerSuffixAreConventionalRouted()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "Saved record employee #211";
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.PostAsync("http://localhost/employeerecords/save/211",
|
||||
new StringContent(string.Empty));
|
||||
|
||||
// Assert
|
||||
response.EnsureSuccessStatusCode();
|
||||
Assert.Equal(expected, await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("generic")]
|
||||
[InlineData("nested")]
|
||||
[InlineData("not-in-services")]
|
||||
public async Task AddControllersFromServices_UsesControllerDiscoveryContentions(string action)
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/not-discovered/" + action);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -40,31 +40,6 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IsControllerValues_LoggedAtStartup()
|
||||
{
|
||||
// Arrange and Act
|
||||
var logs = await GetLogsByDataTypeAsync<IsControllerValues>();
|
||||
|
||||
// Assert
|
||||
Assert.NotEmpty(logs);
|
||||
foreach (var log in logs)
|
||||
{
|
||||
dynamic isController = log.State;
|
||||
if (string.Equals(typeof(HomeController).AssemblyQualifiedName, isController.Type.ToString()))
|
||||
{
|
||||
Assert.Equal(
|
||||
ControllerStatus.IsController,
|
||||
Enum.Parse(typeof(ControllerStatus), isController.Status.ToString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.NotEqual(ControllerStatus.IsController,
|
||||
Enum.Parse(typeof(ControllerStatus), isController.Status.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ControllerModelValues_LoggedAtStartup()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
"BasicWebSite": "1.0.0",
|
||||
"CompositeViewEngineWebSite": "1.0.0",
|
||||
"ConnegWebSite": "1.0.0",
|
||||
"ControllersFromServicesWebSite": "1.0.0",
|
||||
"CustomRouteWebSite": "1.0.0",
|
||||
"ErrorPageMiddlewareWebSite": "1.0.0",
|
||||
"FilesWebSite": "1.0.0",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,153 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.MvcServiceCollectionExtensionsTestControllers;
|
||||
using Microsoft.Framework.ConfigurationModel;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Xunit;
|
||||
|
||||
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(LifecycleKind.Transient, services[0].Lifecycle);
|
||||
|
||||
Assert.Equal(typeof(TypeBController), services[1].ServiceType);
|
||||
Assert.Equal(typeof(TypeBController), services[1].ImplementationType);
|
||||
Assert.Equal(LifecycleKind.Transient, services[1].Lifecycle);
|
||||
|
||||
Assert.Equal(typeof(IControllerActivator), services[2].ServiceType);
|
||||
Assert.Equal(typeof(ServiceBasedControllerActivator), services[2].ImplementationType);
|
||||
Assert.Equal(LifecycleKind.Transient, services[2].Lifecycle);
|
||||
|
||||
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(LifecycleKind.Singleton, services[3].Lifecycle);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WithControllersAsServices_UsesConfigurationIfSpecified()
|
||||
{
|
||||
// Arrange
|
||||
var collection = new ServiceCollection();
|
||||
var controllerTypes = new[] { typeof(ControllerTypeA), typeof(TypeBController) };
|
||||
var configuration = new Configuration();
|
||||
configuration.Add(new MemoryConfigurationSource());
|
||||
configuration.Set(typeof(IControllerActivator).FullName,
|
||||
typeof(CustomActivator).AssemblyQualifiedName);
|
||||
configuration.Set(typeof(IControllerTypeProvider).FullName,
|
||||
typeof(CustomTypeProvider).AssemblyQualifiedName);
|
||||
|
||||
// Act
|
||||
MvcServiceCollectionExtensions.WithControllersAsServices(collection,
|
||||
controllerTypes,
|
||||
configuration);
|
||||
|
||||
// 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(LifecycleKind.Transient, services[0].Lifecycle);
|
||||
|
||||
Assert.Equal(typeof(TypeBController), services[1].ServiceType);
|
||||
Assert.Equal(typeof(TypeBController), services[1].ImplementationType);
|
||||
Assert.Equal(LifecycleKind.Transient, services[1].Lifecycle);
|
||||
|
||||
Assert.Equal(typeof(IControllerActivator), services[2].ServiceType);
|
||||
Assert.Equal(typeof(CustomActivator), services[2].ImplementationType);
|
||||
Assert.Equal(LifecycleKind.Transient, services[2].Lifecycle);
|
||||
|
||||
Assert.Equal(typeof(IControllerTypeProvider), services[3].ServiceType);
|
||||
Assert.Equal(typeof(CustomTypeProvider), services[3].ImplementationType);
|
||||
Assert.Equal(LifecycleKind.Singleton, services[3].Lifecycle);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WithControllersAsServices_ScansControllersFromSpecifiedAssemblies()
|
||||
{
|
||||
// Arrange
|
||||
var collection = new ServiceCollection();
|
||||
var assemblies = new[] { GetType().Assembly };
|
||||
var configuration = new Configuration();
|
||||
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(LifecycleKind.Transient, services[0].Lifecycle);
|
||||
|
||||
Assert.Equal(typeof(TypeBController), services[1].ServiceType);
|
||||
Assert.Equal(typeof(TypeBController), services[1].ImplementationType);
|
||||
Assert.Equal(LifecycleKind.Transient, services[1].Lifecycle);
|
||||
|
||||
|
||||
Assert.Equal(typeof(IControllerActivator), services[2].ServiceType);
|
||||
Assert.Equal(typeof(ServiceBasedControllerActivator), services[2].ImplementationType);
|
||||
Assert.Equal(LifecycleKind.Transient, services[2].Lifecycle);
|
||||
|
||||
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(LifecycleKind.Singleton, services[3].Lifecycle);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ using System.Linq;
|
|||
using System.Reflection;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.ApplicationModels;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
using Microsoft.AspNet.Mvc.Filters;
|
||||
using Microsoft.AspNet.Mvc.WebApiCompatShim;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
|
@ -368,10 +369,11 @@ namespace System.Web.Http
|
|||
|
||||
private INestedProviderManager<ActionDescriptorProviderContext> CreateProvider()
|
||||
{
|
||||
var assemblyProvider = new Mock<IAssemblyProvider>();
|
||||
assemblyProvider
|
||||
.SetupGet(ap => ap.CandidateAssemblies)
|
||||
.Returns(new Assembly[] { typeof(ApiControllerActionDiscoveryTest).Assembly });
|
||||
var assemblyProvider = new FixedSetAssemblyProvider();
|
||||
assemblyProvider.CandidateAssemblies.Add(GetType().GetTypeInfo().Assembly);
|
||||
var controllerTypeProvider = new NamespaceFilteredControllerTypeProvider(assemblyProvider);
|
||||
var modelBuilder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||
NullLoggerFactory.Instance);
|
||||
|
||||
var filterProvider = new Mock<IGlobalFilterProvider>();
|
||||
filterProvider
|
||||
|
|
@ -389,8 +391,8 @@ namespace System.Web.Http
|
|||
.Returns(options);
|
||||
|
||||
var provider = new ControllerActionDescriptorProvider(
|
||||
assemblyProvider.Object,
|
||||
new NamespaceLimitedActionDiscoveryConventions(),
|
||||
controllerTypeProvider,
|
||||
modelBuilder,
|
||||
filterProvider.Object,
|
||||
optionsAccessor.Object,
|
||||
new NullLoggerFactory());
|
||||
|
|
@ -402,18 +404,21 @@ namespace System.Web.Http
|
|||
});
|
||||
}
|
||||
|
||||
private class NamespaceLimitedActionDiscoveryConventions : DefaultControllerModelBuilder
|
||||
private class NamespaceFilteredControllerTypeProvider : DefaultControllerTypeProvider
|
||||
{
|
||||
public NamespaceLimitedActionDiscoveryConventions()
|
||||
: base(new DefaultActionModelBuilder(), new NullLoggerFactory())
|
||||
public NamespaceFilteredControllerTypeProvider(IAssemblyProvider provider)
|
||||
: base(provider, NullLoggerFactory.Instance)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override bool IsController(TypeInfo typeInfo)
|
||||
public override IEnumerable<TypeInfo> ControllerTypes
|
||||
{
|
||||
return
|
||||
typeInfo.Namespace == "System.Web.Http.TestControllers" &&
|
||||
base.IsController(typeInfo);
|
||||
get
|
||||
{
|
||||
return base.ControllerTypes
|
||||
.Where(typeInfo => typeInfo.Namespace == "System.Web.Http.TestControllers");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace ActivatorWebSite
|
|||
{
|
||||
public class PlainController
|
||||
{
|
||||
[Activate]
|
||||
[FromServices]
|
||||
public MyService Service { get; set; }
|
||||
|
||||
[Activate]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace ControllersFromServicesClassLibrary
|
||||
{
|
||||
public class ConstructorInjectionController
|
||||
{
|
||||
public ConstructorInjectionController(IUrlHelper urlHelper,
|
||||
QueryValueService queryService)
|
||||
{
|
||||
UrlHelper = urlHelper;
|
||||
QueryService = queryService;
|
||||
}
|
||||
|
||||
private IUrlHelper UrlHelper { get; }
|
||||
|
||||
private QueryValueService QueryService { get; }
|
||||
|
||||
[Activate]
|
||||
public HttpRequest Request { get; set; }
|
||||
|
||||
[HttpGet("/constructorinjection")]
|
||||
public IActionResult Index()
|
||||
{
|
||||
var content = string.Join(" ",
|
||||
UrlHelper.Action(),
|
||||
QueryService.GetValue(),
|
||||
Request.Headers["Test-Header"]);
|
||||
|
||||
return new ContentResult { Content = content };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="__ToolsVersion__" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>551dc89e-2a13-4cf2-83d7-1add802443d5</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'" Label="Configuration">
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" Label="Configuration">
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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;
|
||||
|
||||
namespace ControllersFromServicesClassLibrary
|
||||
{
|
||||
public class EmployeeRecords : Controller
|
||||
{
|
||||
[HttpPut("/employee/update_records")]
|
||||
public IActionResult UpdateRecords(string recordId)
|
||||
{
|
||||
return Content("Updated record " + recordId);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
// This action uses conventional routing.
|
||||
public IActionResult Save(string id)
|
||||
{
|
||||
return Content("Saved record employee #" + id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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;
|
||||
|
||||
namespace ControllersFromServicesClassLibrary
|
||||
{
|
||||
public class GenericController<TController> : Controller
|
||||
{
|
||||
[HttpGet("/not-discovered/generic")]
|
||||
public IActionResult Index()
|
||||
{
|
||||
return new EmptyResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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;
|
||||
|
||||
namespace ControllersFromServicesClassLibrary
|
||||
{
|
||||
public class NestedControllerOwner
|
||||
{
|
||||
public class NestedController : Controller
|
||||
{
|
||||
[HttpGet("/not-discovered/nested")]
|
||||
public IActionResult Index()
|
||||
{
|
||||
return new EmptyResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Hosting;
|
||||
using Microsoft.AspNet.Http;
|
||||
|
||||
namespace ControllersFromServicesClassLibrary
|
||||
{
|
||||
public class QueryValueService
|
||||
{
|
||||
private readonly HttpContext _context;
|
||||
|
||||
public QueryValueService(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_context = httpContextAccessor.Value;
|
||||
}
|
||||
|
||||
public string GetValue()
|
||||
{
|
||||
return _context.Request.Query["value"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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;
|
||||
|
||||
namespace ControllersFromServicesClassLibrary
|
||||
{
|
||||
public class TimeScheduleController
|
||||
{
|
||||
[HttpGet("/schedule/{id:int}")]
|
||||
public IActionResult GetSchedule(int id)
|
||||
{
|
||||
return new ContentResult { Content = "No schedules available for " + id };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.Mvc": "6.0.0-*",
|
||||
},
|
||||
"frameworks": {
|
||||
"aspnet50": { },
|
||||
"aspnetcore50": { }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="__ToolsVersion__" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>983741b2-4424-4ed1-9b03-7675a67230c8</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'" Label="Configuration">
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" Label="Configuration">
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<DevelopmentServerPort>42994</DevelopmentServerPort>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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;
|
||||
|
||||
namespace ControllersFromServicesWebSite
|
||||
{
|
||||
public class NotInServicesController : Controller
|
||||
{
|
||||
[HttpGet("/not-discovered/not-in-services")]
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.Builder;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using ControllersFromServicesClassLibrary;
|
||||
|
||||
#if ASPNET50
|
||||
using Autofac;
|
||||
using Microsoft.Framework.DependencyInjection.Autofac;
|
||||
#endif
|
||||
|
||||
namespace ControllersFromServicesWebSite
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
var configuration = app.GetTestConfiguration();
|
||||
|
||||
app.UseServices(services =>
|
||||
{
|
||||
services.AddMvc(configuration)
|
||||
.WithControllersAsServices(
|
||||
new[]
|
||||
{
|
||||
typeof(TimeScheduleController).GetTypeInfo().Assembly
|
||||
});
|
||||
|
||||
services.AddTransient<QueryValueService>();
|
||||
|
||||
#if ASPNET50
|
||||
// Create the autofac container
|
||||
var builder = new ContainerBuilder();
|
||||
|
||||
// Create the container and use the default application services as a fallback
|
||||
AutofacRegistration.Populate(
|
||||
builder,
|
||||
services);
|
||||
|
||||
return builder.Build()
|
||||
.Resolve<IServiceProvider>();
|
||||
#endif
|
||||
});
|
||||
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute("default", "{controller}/{action}/{id}");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
<view-data>@ViewBag.Value</view-data>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"commands": {
|
||||
"web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001",
|
||||
"kestrel": "Microsoft.AspNet.Hosting --server Kestrel --server.urls http://localhost:5000"
|
||||
},
|
||||
"dependencies": {
|
||||
"ControllersFromServicesClassLibrary": "1.0.0",
|
||||
"Kestrel": "1.0.0-*",
|
||||
"Microsoft.AspNet.Mvc": "6.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.TestConfiguration": "1.0.0",
|
||||
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
|
||||
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",
|
||||
"Microsoft.AspNet.StaticFiles": "1.0.0-*"
|
||||
},
|
||||
"frameworks": {
|
||||
"aspnet50": {
|
||||
"dependencies": {
|
||||
"Microsoft.Framework.DependencyInjection.Autofac": "1.0.0-*"
|
||||
}
|
||||
},
|
||||
"aspnetcore50": { }
|
||||
},
|
||||
"webroot": "wwwroot"
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
Functional test site for verifying that controllers registered as services can be consumed by DefaultControllerFactory.
|
||||
|
|
@ -14,7 +14,7 @@ namespace ModelBindingWebSite.Controllers
|
|||
private IHtmlHelper<Person> _personHelper;
|
||||
private bool _activated;
|
||||
|
||||
[Activate]
|
||||
[FromServices]
|
||||
public IHtmlHelper<Person> PersonHelper
|
||||
{
|
||||
get
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace MvcTagHelpersWebSite.Controllers
|
|||
{
|
||||
public class Catalog_CacheTagHelperController : Controller
|
||||
{
|
||||
[Activate]
|
||||
[FromServices]
|
||||
public ProductsService ProductsService { get; set; }
|
||||
|
||||
[HttpGet("/catalog")]
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace RequestServicesWebSite
|
|||
[Route("RequestScoped/[action]")]
|
||||
public class RequestScopedServiceController
|
||||
{
|
||||
[Activate]
|
||||
[FromServices]
|
||||
public RequestIdService RequestIdService { get; set; }
|
||||
|
||||
[HttpGet]
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace WebApiCompatShimWebSite
|
|||
{
|
||||
public class BasicApiController : ApiController
|
||||
{
|
||||
[Activate]
|
||||
[FromServices]
|
||||
public IOptions<WebApiCompatShimOptions> OptionsAccessor { get; set; }
|
||||
|
||||
// Verifies property activation
|
||||
|
|
|
|||
Loading…
Reference in New Issue