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
|
EndProject
|
||||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "FormatFilterWebSite", "test\WebSites\FormatFilterWebSite\FormatFilterWebSite.kproj", "{AC9BE567-540E-4C70-90C2-AAF021307A80}"
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "FormatFilterWebSite", "test\WebSites\FormatFilterWebSite\FormatFilterWebSite.kproj", "{AC9BE567-540E-4C70-90C2-AAF021307A80}"
|
||||||
EndProject
|
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}"
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "RazorCompilerCacheWebSite", "test\WebSites\RazorCompilerCacheWebSite\RazorCompilerCacheWebSite.kproj", "{42C5D417-4060-48F4-BB28-E9E179007779}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
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|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.ActiveCfg = Release|Any CPU
|
||||||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Release|x86.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{22019146-BDFA-442E-8C8E-345FB9644578}.Debug|Any CPU.Build.0 = 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
|
{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|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.ActiveCfg = Release|Any CPU
|
||||||
{AC9BE567-540E-4C70-90C2-AAF021307A80}.Release|x86.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{42C5D417-4060-48F4-BB28-E9E179007779}.Debug|Any CPU.Build.0 = 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
|
{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}
|
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||||
{22019146-BDFA-442E-8C8E-345FB9644578} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
{22019146-BDFA-442E-8C8E-345FB9644578} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||||
{AC9BE567-540E-4C70-90C2-AAF021307A80} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
{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}
|
{42C5D417-4060-48F4-BB28-E9E179007779} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ namespace MvcSample.Web
|
||||||
return View("MyView", user);
|
return View("MyView", user);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Activate]
|
[FromServices]
|
||||||
public IHostingEnvironment HostingEnvironment { get; set; }
|
public IHostingEnvironment HostingEnvironment { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNet.Mvc.Description;
|
using Microsoft.AspNet.Mvc.Description;
|
||||||
using Microsoft.AspNet.Mvc.Filters;
|
using Microsoft.AspNet.Mvc.Filters;
|
||||||
using Microsoft.AspNet.Mvc.Logging;
|
|
||||||
using Microsoft.AspNet.Mvc.Routing;
|
using Microsoft.AspNet.Mvc.Routing;
|
||||||
using Microsoft.Framework.Logging;
|
using Microsoft.Framework.Logging;
|
||||||
|
|
||||||
|
|
@ -34,11 +33,6 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ControllerModel BuildControllerModel([NotNull] TypeInfo typeInfo)
|
public ControllerModel BuildControllerModel([NotNull] TypeInfo typeInfo)
|
||||||
{
|
{
|
||||||
if (!IsController(typeInfo))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var controllerModel = CreateControllerModel(typeInfo);
|
var controllerModel = CreateControllerModel(typeInfo);
|
||||||
|
|
||||||
foreach (var methodInfo in typeInfo.AsType().GetMethods())
|
foreach (var methodInfo in typeInfo.AsType().GetMethods())
|
||||||
|
|
@ -57,54 +51,6 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
return controllerModel;
|
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>
|
/// <summary>
|
||||||
/// Creates an <see cref="ControllerModel"/> for the given <see cref="TypeInfo"/>.
|
/// Creates an <see cref="ControllerModel"/> for the given <see cref="TypeInfo"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -100,10 +100,10 @@ namespace Microsoft.AspNet.Mvc
|
||||||
[Activate]
|
[Activate]
|
||||||
public ActionBindingContext BindingContext { get; set; }
|
public ActionBindingContext BindingContext { get; set; }
|
||||||
|
|
||||||
[Activate]
|
[FromServices]
|
||||||
public IModelMetadataProvider MetadataProvider { get; set; }
|
public IModelMetadataProvider MetadataProvider { get; set; }
|
||||||
|
|
||||||
[Activate]
|
[FromServices]
|
||||||
public IUrlHelper Url { get; set; }
|
public IUrlHelper Url { get; set; }
|
||||||
|
|
||||||
public IPrincipal User
|
public IPrincipal User
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.AspNet.Mvc.ApplicationModels;
|
using Microsoft.AspNet.Mvc.ApplicationModels;
|
||||||
using Microsoft.AspNet.Mvc.Filters;
|
using Microsoft.AspNet.Mvc.Filters;
|
||||||
using Microsoft.AspNet.Mvc.Logging;
|
using Microsoft.AspNet.Mvc.Logging;
|
||||||
|
|
@ -15,18 +14,18 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public class ControllerActionDescriptorProvider : IActionDescriptorProvider
|
public class ControllerActionDescriptorProvider : IActionDescriptorProvider
|
||||||
{
|
{
|
||||||
private readonly IControllerModelBuilder _applicationModelBuilder;
|
private readonly IControllerModelBuilder _applicationModelBuilder;
|
||||||
private readonly IAssemblyProvider _assemblyProvider;
|
private readonly IControllerTypeProvider _controllerTypeProvider;
|
||||||
private readonly IReadOnlyList<IFilter> _globalFilters;
|
private readonly IReadOnlyList<IFilter> _globalFilters;
|
||||||
private readonly IEnumerable<IApplicationModelConvention> _conventions;
|
private readonly IEnumerable<IApplicationModelConvention> _conventions;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public ControllerActionDescriptorProvider([NotNull] IAssemblyProvider assemblyProvider,
|
public ControllerActionDescriptorProvider([NotNull] IControllerTypeProvider controllerTypeProvider,
|
||||||
[NotNull] IControllerModelBuilder applicationModelBuilder,
|
[NotNull] IControllerModelBuilder applicationModelBuilder,
|
||||||
[NotNull] IGlobalFilterProvider globalFilters,
|
[NotNull] IGlobalFilterProvider globalFilters,
|
||||||
[NotNull] IOptions<MvcOptions> optionsAccessor,
|
[NotNull] IOptions<MvcOptions> optionsAccessor,
|
||||||
[NotNull] ILoggerFactory loggerFactory)
|
[NotNull] ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
_assemblyProvider = assemblyProvider;
|
_controllerTypeProvider = controllerTypeProvider;
|
||||||
_applicationModelBuilder = applicationModelBuilder;
|
_applicationModelBuilder = applicationModelBuilder;
|
||||||
_globalFilters = globalFilters.Filters;
|
_globalFilters = globalFilters.Filters;
|
||||||
_conventions = optionsAccessor.Options.Conventions;
|
_conventions = optionsAccessor.Options.Conventions;
|
||||||
|
|
@ -66,17 +65,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
applicationModel.Filters.Add(filter);
|
applicationModel.Filters.Add(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
var assemblies = _assemblyProvider.CandidateAssemblies;
|
foreach (var type in _controllerTypeProvider.ControllerTypes)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
var controllerModel = _applicationModelBuilder.BuildControllerModel(type);
|
var controllerModel = _applicationModelBuilder.BuildControllerModel(type);
|
||||||
if (controllerModel != null)
|
if (controllerModel != null)
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
get
|
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;
|
||||||
using System.Collections.Concurrent;
|
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;
|
using Microsoft.Framework.DependencyInjection;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the <see cref="IControllerActivator"/> that is registered by default.
|
/// <see cref="IControllerActivator"/> that uses type activation to create controllers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DefaultControllerActivator : IControllerActivator
|
public class DefaultControllerActivator : IControllerActivator
|
||||||
{
|
{
|
||||||
private readonly Func<Type, PropertyActivator<ActionContext>[]> _getPropertiesToActivate;
|
private static readonly Func<Type, ObjectFactory> _createControllerFactory =
|
||||||
private readonly IDictionary<Type, Func<ActionContext, object>> _valueAccessorLookup;
|
type => ActivatorUtilities.CreateFactory(type, Type.EmptyTypes);
|
||||||
private readonly ConcurrentDictionary<Type, PropertyActivator<ActionContext>[]> _injectActions;
|
|
||||||
|
|
||||||
/// <summary>
|
private readonly ConcurrentDictionary<Type, ObjectFactory> _controllerFactories =
|
||||||
/// Initializes a new instance of the DefaultControllerActivator class.
|
new ConcurrentDictionary<Type, ObjectFactory>();
|
||||||
/// </summary>
|
|
||||||
public DefaultControllerActivator()
|
/// <inheritdoc />
|
||||||
|
public object Create([NotNull] ActionContext actionContext, [NotNull] Type controllerType)
|
||||||
{
|
{
|
||||||
_valueAccessorLookup = CreateValueAccessorLookup();
|
var factory = _controllerFactories.GetOrAdd(controllerType, _createControllerFactory);
|
||||||
_injectActions = new ConcurrentDictionary<Type, PropertyActivator<ActionContext>[]>();
|
return factory(actionContext.HttpContext.RequestServices, arguments: null);
|
||||||
_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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,27 +2,43 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
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.Core;
|
||||||
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.Framework.DependencyInjection;
|
using Microsoft.Framework.DependencyInjection;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default implementation for <see cref="IControllerFactory"/>.
|
||||||
|
/// </summary>
|
||||||
public class DefaultControllerFactory : IControllerFactory
|
public class DefaultControllerFactory : IControllerFactory
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _serviceProvider;
|
|
||||||
private readonly ITypeActivator _typeActivator;
|
|
||||||
private readonly IControllerActivator _controllerActivator;
|
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,
|
/// <summary>
|
||||||
ITypeActivator typeActivator,
|
/// Initializes a new instance of <see cref="DefaultControllerFactory"/>.
|
||||||
IControllerActivator controllerActivator)
|
/// </summary>
|
||||||
|
/// <param name="controllerActivator"><see cref="IControllerActivator"/> used to create controller
|
||||||
|
/// instances.</param>
|
||||||
|
public DefaultControllerFactory(IControllerActivator controllerActivator)
|
||||||
{
|
{
|
||||||
_serviceProvider = serviceProvider;
|
|
||||||
_typeActivator = typeActivator;
|
|
||||||
_controllerActivator = controllerActivator;
|
_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;
|
var actionDescriptor = actionContext.ActionDescriptor as ControllerActionDescriptor;
|
||||||
if (actionDescriptor == null)
|
if (actionDescriptor == null)
|
||||||
|
|
@ -33,15 +49,14 @@ namespace Microsoft.AspNet.Mvc
|
||||||
nameof(actionContext));
|
nameof(actionContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
var controller = _typeActivator.CreateInstance(
|
var controllerType = actionDescriptor.ControllerTypeInfo.AsType();
|
||||||
_serviceProvider,
|
var controller = _controllerActivator.Create(actionContext, controllerType);
|
||||||
actionDescriptor.ControllerTypeInfo.AsType());
|
ActivateProperties(controller, actionContext);
|
||||||
|
|
||||||
_controllerActivator.Activate(controller, actionContext);
|
|
||||||
|
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public void ReleaseController(object controller)
|
public void ReleaseController(object controller)
|
||||||
{
|
{
|
||||||
var disposableController = controller as IDisposable;
|
var disposableController = controller as IDisposable;
|
||||||
|
|
@ -51,5 +66,111 @@ namespace Microsoft.AspNet.Mvc
|
||||||
disposableController.Dispose();
|
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
|
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
|
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; }
|
IEnumerable<Assembly> CandidateAssemblies { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,19 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides methods to activate an instantiated controller.
|
/// Provides methods to create a controller.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IControllerActivator
|
public interface IControllerActivator
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When implemented in a type, activates an instantiated controller.
|
/// Creates a controller.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="controller">The controller to activate.</param>
|
|
||||||
/// <param name="context">The <see cref="ActionContext"/> for the executing action.</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
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides methods for creation and disposal of controllers.
|
||||||
|
/// </summary>
|
||||||
public interface IControllerFactory
|
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);
|
object CreateController(ActionContext actionContext);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases a controller instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="controller">The controller.</param>
|
||||||
void ReleaseController(object controller);
|
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);
|
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>
|
/// <summary>
|
||||||
/// No URL for remote validation could be found.
|
/// No URL for remote validation could be found.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -433,6 +433,9 @@
|
||||||
<data name="Format_NotValid" xml:space="preserve">
|
<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>
|
<value>The format provided is invalid '{0}'. A format must be a non-empty file-extension, optionally prefixed with a '.' character.</value>
|
||||||
</data>
|
</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">
|
<data name="RemoteAttribute_NoUrlFound" xml:space="preserve">
|
||||||
<value>No URL for remote validation could be found.</value>
|
<value>No URL for remote validation could be found.</value>
|
||||||
</data>
|
</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"/>.
|
/// Gets the <see cref="IModelMetadataProvider"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>The setter is intended for unit testing purposes only.</remarks>
|
/// <remarks>The setter is intended for unit testing purposes only.</remarks>
|
||||||
[Activate]
|
[FromServices]
|
||||||
public IModelMetadataProvider MetadataProvider { get; set; }
|
public IModelMetadataProvider MetadataProvider { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -91,7 +91,7 @@ namespace System.Web.Http
|
||||||
/// Gets a factory used to generate URLs to other APIs.
|
/// Gets a factory used to generate URLs to other APIs.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>The setter is intended for unit testing purposes only.</remarks>
|
/// <remarks>The setter is intended for unit testing purposes only.</remarks>
|
||||||
[Activate]
|
[FromServices]
|
||||||
public IUrlHelper Url { get; set; }
|
public IUrlHelper Url { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,13 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using Microsoft.AspNet.Mvc;
|
using Microsoft.AspNet.Mvc;
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.Framework.ConfigurationModel;
|
using Microsoft.Framework.ConfigurationModel;
|
||||||
|
using Microsoft.Framework.Logging;
|
||||||
|
|
||||||
namespace Microsoft.Framework.DependencyInjection
|
namespace Microsoft.Framework.DependencyInjection
|
||||||
{
|
{
|
||||||
|
|
@ -36,6 +40,92 @@ namespace Microsoft.Framework.DependencyInjection
|
||||||
services.Configure(setupAction);
|
services.Configure(setupAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register the specified <paramref name="controllerTypes"/> as services and as a source for controller
|
||||||
|
/// discovery.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
|
||||||
|
/// <param name="controllerTypes">A sequence of controller <see cref="Type"/>s to register in the <paramref name="services"/>
|
||||||
|
/// and used for controller discovery.</param>
|
||||||
|
/// <returns>The <see cref="IServiceCollection"/>.</returns>
|
||||||
|
public static IServiceCollection WithControllersAsServices(
|
||||||
|
[NotNull] this IServiceCollection services,
|
||||||
|
[NotNull] IEnumerable<Type> controllerTypes)
|
||||||
|
{
|
||||||
|
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)
|
private static void ConfigureDefaultServices(IServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
services.AddOptions(configuration);
|
services.AddOptions(configuration);
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,12 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// Core action discovery, filters and action execution.
|
// Core action discovery, filters and action execution.
|
||||||
|
|
||||||
// These are consumed only when creating action descriptors, then they can be de-allocated
|
// 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<IControllerModelBuilder, DefaultControllerModelBuilder>();
|
||||||
yield return describe.Transient<IActionModelBuilder, DefaultActionModelBuilder>();
|
yield return describe.Transient<IActionModelBuilder, DefaultActionModelBuilder>();
|
||||||
|
|
||||||
// This accesses per-request services to activate the controller
|
// This has a cache, so it needs to be a singleton
|
||||||
yield return describe.Transient<IControllerFactory, DefaultControllerFactory>();
|
yield return describe.Singleton<IControllerFactory, DefaultControllerFactory>();
|
||||||
|
|
||||||
// This has a cache, so it needs to be a singleton
|
// This has a cache, so it needs to be a singleton
|
||||||
yield return describe.Singleton<IControllerActivator, DefaultControllerActivator>();
|
yield return describe.Singleton<IControllerActivator, DefaultControllerActivator>();
|
||||||
|
|
|
||||||
|
|
@ -1,176 +1,22 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
// 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.
|
// 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;
|
||||||
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Mvc.Filters;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ApplicationModels
|
namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
{
|
{
|
||||||
public class DefaultControllerModelBuilderTest
|
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]
|
[Fact]
|
||||||
public void BuildControllerModel_DerivedFromControllerClass_HasFilter()
|
public void BuildControllerModel_DerivedFromControllerClass_HasFilter()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var builder = new AccessibleControllerModelBuilder();
|
var builder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||||
|
NullLoggerFactory.Instance);
|
||||||
var typeInfo = typeof(StoreController).GetTypeInfo();
|
var typeInfo = typeof(StoreController).GetTypeInfo();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -187,7 +33,8 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
public void BuildControllerModel_ClassWithoutFilterInterfaces_HasNoControllerFilter()
|
public void BuildControllerModel_ClassWithoutFilterInterfaces_HasNoControllerFilter()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var builder = new AccessibleControllerModelBuilder();
|
var builder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||||
|
NullLoggerFactory.Instance);
|
||||||
var typeInfo = typeof(NoFiltersController).GetTypeInfo();
|
var typeInfo = typeof(NoFiltersController).GetTypeInfo();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -202,7 +49,8 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
public void BuildControllerModel_ClassWithFilterInterfaces_HasFilter()
|
public void BuildControllerModel_ClassWithFilterInterfaces_HasFilter()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var builder = new AccessibleControllerModelBuilder();
|
var builder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||||
|
NullLoggerFactory.Instance);
|
||||||
var typeInfo = typeof(SomeFiltersController).GetTypeInfo();
|
var typeInfo = typeof(SomeFiltersController).GetTypeInfo();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -217,7 +65,8 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
public void BuildControllerModel_ClassWithFilterInterfaces_UnsupportedType()
|
public void BuildControllerModel_ClassWithFilterInterfaces_UnsupportedType()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var builder = new AccessibleControllerModelBuilder();
|
var builder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||||
|
NullLoggerFactory.Instance);
|
||||||
var typeInfo = typeof(UnsupportedFiltersController).GetTypeInfo();
|
var typeInfo = typeof(UnsupportedFiltersController).GetTypeInfo();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -227,102 +76,49 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||||
Assert.Empty(model.Filters);
|
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,
|
TypeInfo controllerTypeInfo,
|
||||||
IEnumerable<IFilter> filters = null)
|
IEnumerable<IFilter> filters = null)
|
||||||
{
|
{
|
||||||
var modelBuilder = new StaticControllerModelBuilder(controllerTypeInfo);
|
var controllerTypeProvider = new FixedSetControllerTypeProvider(new[] { controllerTypeInfo });
|
||||||
|
var controllerModelBuilder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||||
var assemblyProvider = new Mock<IAssemblyProvider>();
|
NullLoggerFactory.Instance);
|
||||||
assemblyProvider
|
|
||||||
.SetupGet(ap => ap.CandidateAssemblies)
|
|
||||||
.Returns(new Assembly[] { controllerTypeInfo.Assembly });
|
|
||||||
|
|
||||||
var provider = new ControllerActionDescriptorProvider(
|
var provider = new ControllerActionDescriptorProvider(
|
||||||
assemblyProvider.Object,
|
controllerTypeProvider,
|
||||||
modelBuilder,
|
controllerModelBuilder,
|
||||||
new TestGlobalFilterProvider(filters),
|
new TestGlobalFilterProvider(filters),
|
||||||
new MockMvcOptionsAccessor(),
|
new MockMvcOptionsAccessor(),
|
||||||
new NullLoggerFactory());
|
new NullLoggerFactory());
|
||||||
|
|
@ -1382,16 +1379,13 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
private ControllerActionDescriptorProvider GetProvider(
|
private ControllerActionDescriptorProvider GetProvider(
|
||||||
params TypeInfo[] controllerTypeInfo)
|
params TypeInfo[] controllerTypeInfo)
|
||||||
{
|
{
|
||||||
var modelBuilder = new StaticControllerModelBuilder(controllerTypeInfo);
|
var controllerTypeProvider = new FixedSetControllerTypeProvider(controllerTypeInfo);
|
||||||
|
var controllerModelBuilder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||||
var assemblyProvider = new Mock<IAssemblyProvider>();
|
NullLoggerFactory.Instance);
|
||||||
assemblyProvider
|
|
||||||
.SetupGet(ap => ap.CandidateAssemblies)
|
|
||||||
.Returns(new Assembly[] { controllerTypeInfo.First().Assembly });
|
|
||||||
|
|
||||||
var provider = new ControllerActionDescriptorProvider(
|
var provider = new ControllerActionDescriptorProvider(
|
||||||
assemblyProvider.Object,
|
controllerTypeProvider,
|
||||||
modelBuilder,
|
controllerModelBuilder,
|
||||||
new TestGlobalFilterProvider(),
|
new TestGlobalFilterProvider(),
|
||||||
new MockMvcOptionsAccessor(),
|
new MockMvcOptionsAccessor(),
|
||||||
new NullLoggerFactory());
|
new NullLoggerFactory());
|
||||||
|
|
@ -1403,18 +1397,15 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
TypeInfo type,
|
TypeInfo type,
|
||||||
IApplicationModelConvention convention)
|
IApplicationModelConvention convention)
|
||||||
{
|
{
|
||||||
var modelBuilder = new StaticControllerModelBuilder(type);
|
var controllerTypeProvider = new FixedSetControllerTypeProvider(new[] { type });
|
||||||
|
var modelBuilder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||||
var assemblyProvider = new Mock<IAssemblyProvider>();
|
NullLoggerFactory.Instance);
|
||||||
assemblyProvider
|
|
||||||
.SetupGet(ap => ap.CandidateAssemblies)
|
|
||||||
.Returns(new Assembly[] { type.Assembly });
|
|
||||||
|
|
||||||
var options = new MockMvcOptionsAccessor();
|
var options = new MockMvcOptionsAccessor();
|
||||||
options.Options.Conventions.Add(convention);
|
options.Options.Conventions.Add(convention);
|
||||||
|
|
||||||
return new ControllerActionDescriptorProvider(
|
return new ControllerActionDescriptorProvider(
|
||||||
assemblyProvider.Object,
|
controllerTypeProvider,
|
||||||
modelBuilder,
|
modelBuilder,
|
||||||
new TestGlobalFilterProvider(),
|
new TestGlobalFilterProvider(),
|
||||||
options,
|
options,
|
||||||
|
|
@ -1423,15 +1414,12 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
|
|
||||||
private IEnumerable<ActionDescriptor> GetDescriptors(params TypeInfo[] controllerTypeInfos)
|
private IEnumerable<ActionDescriptor> GetDescriptors(params TypeInfo[] controllerTypeInfos)
|
||||||
{
|
{
|
||||||
var modelBuilder = new StaticControllerModelBuilder(controllerTypeInfos);
|
var controllerTypeProvider = new FixedSetControllerTypeProvider(controllerTypeInfos);
|
||||||
|
var modelBuilder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||||
var assemblyProvider = new Mock<IAssemblyProvider>();
|
NullLoggerFactory.Instance);
|
||||||
assemblyProvider
|
|
||||||
.SetupGet(ap => ap.CandidateAssemblies)
|
|
||||||
.Returns(controllerTypeInfos.Select(cti => cti.Assembly).Distinct());
|
|
||||||
|
|
||||||
var provider = new ControllerActionDescriptorProvider(
|
var provider = new ControllerActionDescriptorProvider(
|
||||||
assemblyProvider.Object,
|
controllerTypeProvider,
|
||||||
modelBuilder,
|
modelBuilder,
|
||||||
new TestGlobalFilterProvider(),
|
new TestGlobalFilterProvider(),
|
||||||
new MockMvcOptionsAccessor(),
|
new MockMvcOptionsAccessor(),
|
||||||
|
|
|
||||||
|
|
@ -8,32 +8,12 @@ using Microsoft.AspNet.Mvc.ApplicationModels;
|
||||||
using Microsoft.Framework.DependencyInjection;
|
using Microsoft.Framework.DependencyInjection;
|
||||||
using Microsoft.Framework.DependencyInjection.NestedProviders;
|
using Microsoft.Framework.DependencyInjection.NestedProviders;
|
||||||
using Microsoft.Framework.Logging;
|
using Microsoft.Framework.Logging;
|
||||||
using Moq;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Logging
|
namespace Microsoft.AspNet.Mvc.Logging
|
||||||
{
|
{
|
||||||
public class DefaultActionDescriptorCollectionProviderLoggingTest
|
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]
|
[Fact]
|
||||||
public void ControllerDiscovery()
|
public void ControllerDiscovery()
|
||||||
{
|
{
|
||||||
|
|
@ -49,10 +29,10 @@ namespace Microsoft.AspNet.Mvc.Logging
|
||||||
provider.GetDescriptors();
|
provider.GetDescriptors();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
// 1 assembly, 2 controllers
|
// 2 controllers
|
||||||
Assert.Equal(3, sink.Writes.Count);
|
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.NotNull(controllerModelValues);
|
||||||
Assert.Equal("Simple", controllerModelValues.ControllerName);
|
Assert.Equal("Simple", controllerModelValues.ControllerName);
|
||||||
Assert.Equal(typeof(SimpleController), controllerModelValues.ControllerType);
|
Assert.Equal(typeof(SimpleController), controllerModelValues.ControllerType);
|
||||||
|
|
@ -62,7 +42,7 @@ namespace Microsoft.AspNet.Mvc.Logging
|
||||||
Assert.Empty(controllerModelValues.Attributes);
|
Assert.Empty(controllerModelValues.Attributes);
|
||||||
Assert.Empty(controllerModelValues.Filters);
|
Assert.Empty(controllerModelValues.Filters);
|
||||||
|
|
||||||
controllerModelValues = sink.Writes[2].State as ControllerModelValues;
|
controllerModelValues = Assert.IsType<ControllerModelValues>(sink.Writes[1].State);
|
||||||
Assert.NotNull(controllerModelValues);
|
Assert.NotNull(controllerModelValues);
|
||||||
Assert.Equal("Basic", controllerModelValues.ControllerName);
|
Assert.Equal("Basic", controllerModelValues.ControllerName);
|
||||||
Assert.Equal(typeof(BasicController), controllerModelValues.ControllerType);
|
Assert.Equal(typeof(BasicController), controllerModelValues.ControllerType);
|
||||||
|
|
@ -88,10 +68,12 @@ namespace Microsoft.AspNet.Mvc.Logging
|
||||||
typeof(BasicController).GetTypeInfo());
|
typeof(BasicController).GetTypeInfo());
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
// 1 assembly, 2 controllers, 3 actions
|
// 2 controllers, 3 actions
|
||||||
Assert.Equal(6, sink.Writes.Count);
|
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.NotNull(actionDescriptorValues);
|
||||||
Assert.Equal("EmptyAction", actionDescriptorValues.Name);
|
Assert.Equal("EmptyAction", actionDescriptorValues.Name);
|
||||||
Assert.Equal("Simple", actionDescriptorValues.ControllerName);
|
Assert.Equal("Simple", actionDescriptorValues.ControllerName);
|
||||||
|
|
@ -101,7 +83,7 @@ namespace Microsoft.AspNet.Mvc.Logging
|
||||||
Assert.Empty(actionDescriptorValues.FilterDescriptors);
|
Assert.Empty(actionDescriptorValues.FilterDescriptors);
|
||||||
Assert.Empty(actionDescriptorValues.Parameters);
|
Assert.Empty(actionDescriptorValues.Parameters);
|
||||||
|
|
||||||
actionDescriptorValues = sink.Writes[4].State as ActionDescriptorValues;
|
actionDescriptorValues = Assert.IsType<ActionDescriptorValues>(sink.Writes[3].State);
|
||||||
Assert.NotNull(actionDescriptorValues);
|
Assert.NotNull(actionDescriptorValues);
|
||||||
Assert.Equal("Basic", actionDescriptorValues.Name);
|
Assert.Equal("Basic", actionDescriptorValues.Name);
|
||||||
Assert.Equal("Basic", actionDescriptorValues.ControllerName);
|
Assert.Equal("Basic", actionDescriptorValues.ControllerName);
|
||||||
|
|
@ -111,7 +93,7 @@ namespace Microsoft.AspNet.Mvc.Logging
|
||||||
Assert.Equal(2, actionDescriptorValues.FilterDescriptors.Count);
|
Assert.Equal(2, actionDescriptorValues.FilterDescriptors.Count);
|
||||||
Assert.Empty(actionDescriptorValues.Parameters);
|
Assert.Empty(actionDescriptorValues.Parameters);
|
||||||
|
|
||||||
actionDescriptorValues = sink.Writes[5].State as ActionDescriptorValues;
|
actionDescriptorValues = Assert.IsType<ActionDescriptorValues>(sink.Writes[4].State);
|
||||||
Assert.NotNull(actionDescriptorValues);
|
Assert.NotNull(actionDescriptorValues);
|
||||||
Assert.Equal("Basic", actionDescriptorValues.Name);
|
Assert.Equal("Basic", actionDescriptorValues.Name);
|
||||||
Assert.Equal("Basic", actionDescriptorValues.ControllerName);
|
Assert.Equal("Basic", actionDescriptorValues.ControllerName);
|
||||||
|
|
@ -140,15 +122,12 @@ namespace Microsoft.AspNet.Mvc.Logging
|
||||||
private ControllerActionDescriptorProvider GetProvider(
|
private ControllerActionDescriptorProvider GetProvider(
|
||||||
ILoggerFactory loggerFactory, params TypeInfo[] controllerTypeInfo)
|
ILoggerFactory loggerFactory, params TypeInfo[] controllerTypeInfo)
|
||||||
{
|
{
|
||||||
var modelBuilder = new StaticControllerModelBuilder(controllerTypeInfo);
|
var controllerTypeProvider = new FixedSetControllerTypeProvider(controllerTypeInfo);
|
||||||
|
var modelBuilder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||||
var assemblyProvider = new Mock<IAssemblyProvider>();
|
loggerFactory);
|
||||||
assemblyProvider
|
|
||||||
.SetupGet(ap => ap.CandidateAssemblies)
|
|
||||||
.Returns(new Assembly[] { controllerTypeInfo.First().Assembly });
|
|
||||||
|
|
||||||
var provider = new ControllerActionDescriptorProvider(
|
var provider = new ControllerActionDescriptorProvider(
|
||||||
assemblyProvider.Object,
|
controllerTypeProvider,
|
||||||
modelBuilder,
|
modelBuilder,
|
||||||
new TestGlobalFilterProvider(),
|
new TestGlobalFilterProvider(),
|
||||||
new MockMvcOptionsAccessor(),
|
new MockMvcOptionsAccessor(),
|
||||||
|
|
|
||||||
|
|
@ -759,16 +759,17 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
private ControllerActionDescriptorProvider GetActionDescriptorProvider()
|
private ControllerActionDescriptorProvider GetActionDescriptorProvider()
|
||||||
{
|
{
|
||||||
var assemblyProvider = new StaticAssemblyProvider();
|
|
||||||
|
|
||||||
var controllerTypes = typeof(DefaultActionSelectorTests)
|
var controllerTypes = typeof(DefaultActionSelectorTests)
|
||||||
.GetNestedTypes(BindingFlags.NonPublic)
|
.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(
|
return new ControllerActionDescriptorProvider(
|
||||||
assemblyProvider,
|
controllerTypeProvider,
|
||||||
modelBuilder,
|
modelBuilder,
|
||||||
new TestGlobalFilterProvider(),
|
new TestGlobalFilterProvider(),
|
||||||
new MockMvcOptionsAccessor(),
|
new MockMvcOptionsAccessor(),
|
||||||
|
|
|
||||||
|
|
@ -1,182 +1,79 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
#if ASPNET50
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http.Core;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
|
||||||
using Microsoft.AspNet.Routing;
|
using Microsoft.AspNet.Routing;
|
||||||
using Microsoft.Framework.DependencyInjection;
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Core.Test
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class DefaultControllerActivatorTest
|
public class DefaultControllerActivatorTest
|
||||||
{
|
{
|
||||||
[Fact]
|
[Theory]
|
||||||
public void Activate_SetsPropertiesFromActionContextHierarchy()
|
[InlineData(typeof(TypeDerivingFromController))]
|
||||||
|
[InlineData(typeof(PocoType))]
|
||||||
|
public void Create_CreatesInstancesOfTypes(Type type)
|
||||||
{
|
{
|
||||||
// Arrange
|
// 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 activator = new DefaultControllerActivator();
|
||||||
|
var actionContext = new ActionContext(new DefaultHttpContext(),
|
||||||
|
new RouteData(),
|
||||||
|
new ActionDescriptor());
|
||||||
// Act
|
// Act
|
||||||
activator.Activate(controller, context);
|
var instance = activator.Create(actionContext, type);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(context, controller.ActionContext);
|
Assert.IsType(type, instance);
|
||||||
Assert.Same(httpContext.Object, controller.HttpContext);
|
|
||||||
Assert.Same(httpRequest, controller.GetHttpRequest());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Activate_SetsViewDatDictionary()
|
public void Create_TypeActivatesTypesWithServices()
|
||||||
{
|
{
|
||||||
// Arrange
|
// 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();
|
var activator = new DefaultControllerActivator();
|
||||||
|
var serviceProvider = new Mock<IServiceProvider>(MockBehavior.Strict);
|
||||||
// Act
|
var testService = new TestService();
|
||||||
activator.Activate(controller, context);
|
serviceProvider.Setup(s => s.GetService(typeof(TestService)))
|
||||||
|
.Returns(testService)
|
||||||
// Assert
|
.Verifiable();
|
||||||
Assert.NotNull(controller.GetViewData());
|
var httpContext = new DefaultHttpContext
|
||||||
}
|
|
||||||
|
|
||||||
[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()
|
|
||||||
{
|
{
|
||||||
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()
|
public TestService TestService { get; }
|
||||||
{
|
}
|
||||||
return Request;
|
|
||||||
}
|
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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
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 Microsoft.Framework.DependencyInjection;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Core.Test
|
namespace Microsoft.AspNet.Mvc.Core
|
||||||
{
|
{
|
||||||
public class DefaultControllerFactoryTest
|
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]
|
[Fact]
|
||||||
public void DefaultControllerFactory_DisposesIDisposableController()
|
public void DefaultControllerFactory_DisposesIDisposableController()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var factory = new DefaultControllerFactory(
|
var factory = new DefaultControllerFactory(Mock.Of<IControllerActivator>());
|
||||||
Mock.Of<IServiceProvider>(),
|
|
||||||
Mock.Of<ITypeActivator>(),
|
|
||||||
Mock.Of<IControllerActivator>());
|
|
||||||
|
|
||||||
var controller = new MyController();
|
var controller = new MyController();
|
||||||
|
|
||||||
// Act + Assert
|
// Act + Assert
|
||||||
|
|
@ -33,17 +259,64 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
public void DefaultControllerFactory_ReleasesNonIDisposableController()
|
public void DefaultControllerFactory_ReleasesNonIDisposableController()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var factory = new DefaultControllerFactory(
|
var factory = new DefaultControllerFactory(Mock.Of<IControllerActivator>());
|
||||||
Mock.Of<IServiceProvider>(),
|
var controller = new object();
|
||||||
Mock.Of<ITypeActivator>(),
|
|
||||||
Mock.Of<IControllerActivator>());
|
|
||||||
|
|
||||||
var controller = new Object();
|
|
||||||
|
|
||||||
// Act + Assert (does not throw)
|
// Act + Assert (does not throw)
|
||||||
factory.ReleaseController(controller);
|
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
|
private class MyController : Controller
|
||||||
{
|
{
|
||||||
public bool Disposed { get; set; }
|
public bool Disposed { get; set; }
|
||||||
|
|
@ -53,5 +326,16 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
||||||
Disposed = true;
|
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
|
private class FilteredViewComponentSelector : DefaultViewComponentSelector
|
||||||
{
|
{
|
||||||
public FilteredViewComponentSelector()
|
public FilteredViewComponentSelector()
|
||||||
: base(new StaticAssemblyProvider())
|
: base(GetAssemblyProvider())
|
||||||
{
|
{
|
||||||
AllowedTypes = typeof(DefaultViewComponentSelectorTest).GetNestedTypes(BindingFlags.NonPublic);
|
AllowedTypes = typeof(DefaultViewComponentSelectorTest).GetNestedTypes(BindingFlags.NonPublic);
|
||||||
}
|
}
|
||||||
|
|
@ -188,6 +188,15 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
return AllowedTypes.Contains(typeInfo.AsType());
|
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 server = TestServer.Create(_provider, _app);
|
||||||
var client = server.CreateClient();
|
var client = server.CreateClient();
|
||||||
|
|
||||||
var expectedMessage = "No service for type 'ActivatorWebSite.CannotBeActivatedController+FakeType' " +
|
var expectedMessage = "The property 'Service' on controller 'ActivatorWebSite.CannotBeActivatedController' " +
|
||||||
"has been registered.";
|
"cannot be activated.";
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
var response = await client.GetAsync("http://localhost/CannotBeActivated/Index");
|
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]
|
[Fact]
|
||||||
public async Task ControllerModelValues_LoggedAtStartup()
|
public async Task ControllerModelValues_LoggedAtStartup()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
"BasicWebSite": "1.0.0",
|
"BasicWebSite": "1.0.0",
|
||||||
"CompositeViewEngineWebSite": "1.0.0",
|
"CompositeViewEngineWebSite": "1.0.0",
|
||||||
"ConnegWebSite": "1.0.0",
|
"ConnegWebSite": "1.0.0",
|
||||||
|
"ControllersFromServicesWebSite": "1.0.0",
|
||||||
"CustomRouteWebSite": "1.0.0",
|
"CustomRouteWebSite": "1.0.0",
|
||||||
"ErrorPageMiddlewareWebSite": "1.0.0",
|
"ErrorPageMiddlewareWebSite": "1.0.0",
|
||||||
"FilesWebSite": "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 System.Reflection;
|
||||||
using Microsoft.AspNet.Mvc;
|
using Microsoft.AspNet.Mvc;
|
||||||
using Microsoft.AspNet.Mvc.ApplicationModels;
|
using Microsoft.AspNet.Mvc.ApplicationModels;
|
||||||
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Microsoft.AspNet.Mvc.Filters;
|
using Microsoft.AspNet.Mvc.Filters;
|
||||||
using Microsoft.AspNet.Mvc.WebApiCompatShim;
|
using Microsoft.AspNet.Mvc.WebApiCompatShim;
|
||||||
using Microsoft.Framework.DependencyInjection;
|
using Microsoft.Framework.DependencyInjection;
|
||||||
|
|
@ -368,10 +369,11 @@ namespace System.Web.Http
|
||||||
|
|
||||||
private INestedProviderManager<ActionDescriptorProviderContext> CreateProvider()
|
private INestedProviderManager<ActionDescriptorProviderContext> CreateProvider()
|
||||||
{
|
{
|
||||||
var assemblyProvider = new Mock<IAssemblyProvider>();
|
var assemblyProvider = new FixedSetAssemblyProvider();
|
||||||
assemblyProvider
|
assemblyProvider.CandidateAssemblies.Add(GetType().GetTypeInfo().Assembly);
|
||||||
.SetupGet(ap => ap.CandidateAssemblies)
|
var controllerTypeProvider = new NamespaceFilteredControllerTypeProvider(assemblyProvider);
|
||||||
.Returns(new Assembly[] { typeof(ApiControllerActionDiscoveryTest).Assembly });
|
var modelBuilder = new DefaultControllerModelBuilder(new DefaultActionModelBuilder(),
|
||||||
|
NullLoggerFactory.Instance);
|
||||||
|
|
||||||
var filterProvider = new Mock<IGlobalFilterProvider>();
|
var filterProvider = new Mock<IGlobalFilterProvider>();
|
||||||
filterProvider
|
filterProvider
|
||||||
|
|
@ -389,8 +391,8 @@ namespace System.Web.Http
|
||||||
.Returns(options);
|
.Returns(options);
|
||||||
|
|
||||||
var provider = new ControllerActionDescriptorProvider(
|
var provider = new ControllerActionDescriptorProvider(
|
||||||
assemblyProvider.Object,
|
controllerTypeProvider,
|
||||||
new NamespaceLimitedActionDiscoveryConventions(),
|
modelBuilder,
|
||||||
filterProvider.Object,
|
filterProvider.Object,
|
||||||
optionsAccessor.Object,
|
optionsAccessor.Object,
|
||||||
new NullLoggerFactory());
|
new NullLoggerFactory());
|
||||||
|
|
@ -402,18 +404,21 @@ namespace System.Web.Http
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NamespaceLimitedActionDiscoveryConventions : DefaultControllerModelBuilder
|
private class NamespaceFilteredControllerTypeProvider : DefaultControllerTypeProvider
|
||||||
{
|
{
|
||||||
public NamespaceLimitedActionDiscoveryConventions()
|
public NamespaceFilteredControllerTypeProvider(IAssemblyProvider provider)
|
||||||
: base(new DefaultActionModelBuilder(), new NullLoggerFactory())
|
: base(provider, NullLoggerFactory.Instance)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool IsController(TypeInfo typeInfo)
|
public override IEnumerable<TypeInfo> ControllerTypes
|
||||||
{
|
{
|
||||||
return
|
get
|
||||||
typeInfo.Namespace == "System.Web.Http.TestControllers" &&
|
{
|
||||||
base.IsController(typeInfo);
|
return base.ControllerTypes
|
||||||
|
.Where(typeInfo => typeInfo.Namespace == "System.Web.Http.TestControllers");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ namespace ActivatorWebSite
|
||||||
{
|
{
|
||||||
public class PlainController
|
public class PlainController
|
||||||
{
|
{
|
||||||
[Activate]
|
[FromServices]
|
||||||
public MyService Service { get; set; }
|
public MyService Service { get; set; }
|
||||||
|
|
||||||
[Activate]
|
[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 IHtmlHelper<Person> _personHelper;
|
||||||
private bool _activated;
|
private bool _activated;
|
||||||
|
|
||||||
[Activate]
|
[FromServices]
|
||||||
public IHtmlHelper<Person> PersonHelper
|
public IHtmlHelper<Person> PersonHelper
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ namespace MvcTagHelpersWebSite.Controllers
|
||||||
{
|
{
|
||||||
public class Catalog_CacheTagHelperController : Controller
|
public class Catalog_CacheTagHelperController : Controller
|
||||||
{
|
{
|
||||||
[Activate]
|
[FromServices]
|
||||||
public ProductsService ProductsService { get; set; }
|
public ProductsService ProductsService { get; set; }
|
||||||
|
|
||||||
[HttpGet("/catalog")]
|
[HttpGet("/catalog")]
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ namespace RequestServicesWebSite
|
||||||
[Route("RequestScoped/[action]")]
|
[Route("RequestScoped/[action]")]
|
||||||
public class RequestScopedServiceController
|
public class RequestScopedServiceController
|
||||||
{
|
{
|
||||||
[Activate]
|
[FromServices]
|
||||||
public RequestIdService RequestIdService { get; set; }
|
public RequestIdService RequestIdService { get; set; }
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ namespace WebApiCompatShimWebSite
|
||||||
{
|
{
|
||||||
public class BasicApiController : ApiController
|
public class BasicApiController : ApiController
|
||||||
{
|
{
|
||||||
[Activate]
|
[FromServices]
|
||||||
public IOptions<WebApiCompatShimOptions> OptionsAccessor { get; set; }
|
public IOptions<WebApiCompatShimOptions> OptionsAccessor { get; set; }
|
||||||
|
|
||||||
// Verifies property activation
|
// Verifies property activation
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue