Fix for issue #610 - Ignore internal and nested types

This change exludes internal and nested types from being treated as
controllers. This is consistent with MVC5's behavior.

DefaultActionSelectionConventions was primarily tested through running
action selection. I wanted to also test the methods with substantial logic
in this class, so I moved a spate of a classes from private classes inside of the
integration tests to public classes so they could be shared. I also added
tests to fill gaps in DefaultActionSelectionConventions, which is the vast
vast majority of this change.
This commit is contained in:
Ryan Nowak 2014-07-15 14:05:24 -07:00
parent 9f8c656b31
commit bff94f169f
7 changed files with 521 additions and 231 deletions

View File

@ -35,6 +35,10 @@ namespace Microsoft.AspNet.Mvc
{
if (!typeInfo.IsClass ||
typeInfo.IsAbstract ||
// We only consider public top-level classes as controllers. IsPublic returns false for nested
// classes, regardless of visibility modifiers.
!typeInfo.IsPublic ||
typeInfo.ContainsGenericParameters)
{
return false;
@ -84,7 +88,7 @@ namespace Microsoft.AspNet.Mvc
/// </summary>
/// <param name="method">The <see cref="MethodInfo"/>.</param>
/// <returns>true if the method is a valid action. Otherwise, false.</returns>
protected virtual bool IsValidActionMethod(MethodInfo method)
public virtual bool IsValidActionMethod(MethodInfo method)
{
return
method.IsPublic &&

View File

@ -20,9 +20,6 @@ namespace Microsoft.AspNet.Mvc.Test
{
public class ActionAttributeTests
{
private DefaultActionDiscoveryConventions _actionDiscoveryConventions = new DefaultActionDiscoveryConventions();
private IEnumerable<Assembly> _controllerAssemblies = new[] { Assembly.GetExecutingAssembly() };
[Theory]
[InlineData("GET")]
[InlineData("PUT")]
@ -116,7 +113,7 @@ namespace Microsoft.AspNet.Mvc.Test
public void NonActionAttribute_ActionNotReachable(string actionName)
{
// Arrange
var actionDescriptorProvider = GetActionDescriptorProvider(_actionDiscoveryConventions);
var actionDescriptorProvider = GetActionDescriptorProvider();
// Act
var result = actionDescriptorProvider.GetDescriptors()
@ -185,13 +182,9 @@ namespace Microsoft.AspNet.Mvc.Test
Assert.Equal(actionName, result.Name);
}
private async Task<ActionDescriptor> InvokeActionSelector(RouteContext context)
{
return await InvokeActionSelector(context, _actionDiscoveryConventions);
}
private async Task<ActionDescriptor> InvokeActionSelector(RouteContext context,
DefaultActionDiscoveryConventions actionDiscoveryConventions)
private async Task<ActionDescriptor> InvokeActionSelector(
RouteContext context,
IActionDiscoveryConventions actionDiscoveryConventions = null)
{
var actionDescriptorProvider = GetActionDescriptorProvider(actionDiscoveryConventions);
var descriptorProvider =
@ -211,13 +204,22 @@ namespace Microsoft.AspNet.Mvc.Test
return await defaultActionSelector.SelectAsync(context);
}
private ReflectedActionDescriptorProvider GetActionDescriptorProvider(DefaultActionDiscoveryConventions actionDiscoveryConventions)
private ReflectedActionDescriptorProvider GetActionDescriptorProvider(
IActionDiscoveryConventions actionDiscoveryConventions = null)
{
var controllerAssemblyProvider = new Mock<IControllerAssemblyProvider>();
controllerAssemblyProvider.SetupGet(x => x.CandidateAssemblies).Returns(_controllerAssemblies);
var controllerAssemblyProvider = new StaticControllerAssemblyProvider();
if (actionDiscoveryConventions == null)
{
var controllerTypes = typeof(ActionAttributeTests)
.GetNestedTypes(BindingFlags.NonPublic)
.Select(t => t.GetTypeInfo());
actionDiscoveryConventions = new StaticActionDiscoveryConventions(controllerTypes.ToArray());
}
return new ReflectedActionDescriptorProvider(
controllerAssemblyProvider.Object,
controllerAssemblyProvider,
actionDiscoveryConventions,
null,
new MockMvcOptionsAccessor(),

View File

@ -9,8 +9,8 @@ using System.ComponentModel.Design;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.DependencyInjection.NestedProviders;
using Moq;
@ -18,11 +18,8 @@ using Xunit;
namespace Microsoft.AspNet.Mvc.Test
{
public class ActionSelectionConventionTests
public class DefaultActionDiscoveryConventionsActionSelectionTests
{
private DefaultActionDiscoveryConventions _actionDiscoveryConventions = new DefaultActionDiscoveryConventions();
private IEnumerable<Assembly> _controllerAssemblies = new[] { Assembly.GetExecutingAssembly() };
[Theory]
[InlineData("GET")]
[InlineData("POST")]
@ -156,10 +153,16 @@ namespace Microsoft.AspNet.Mvc.Test
private async Task<ActionDescriptor> InvokeActionSelector(RouteContext context)
{
return await InvokeActionSelector(context, _actionDiscoveryConventions);
var controllerTypeInfos = typeof(DefaultActionDiscoveryConventionsActionSelectionTests)
.GetNestedTypes(BindingFlags.NonPublic)
.Select(ct => ct.GetTypeInfo())
.ToArray();
var conventions = new StaticActionDiscoveryConventions(controllerTypeInfos);
return await InvokeActionSelector(context, conventions);
}
private async Task<ActionDescriptor> InvokeActionSelector(RouteContext context,
private async Task<ActionDescriptor> InvokeActionSelector(RouteContext context,
DefaultActionDiscoveryConventions actionDiscoveryConventions)
{
var actionDescriptorProvider = GetActionDescriptorProvider(actionDiscoveryConventions);
@ -182,8 +185,9 @@ namespace Microsoft.AspNet.Mvc.Test
private ReflectedActionDescriptorProvider GetActionDescriptorProvider(DefaultActionDiscoveryConventions actionDiscoveryConventions)
{
var assemblies = new Assembly[] { typeof(DefaultActionDiscoveryConventionsActionSelectionTests).GetTypeInfo().Assembly, };
var controllerAssemblyProvider = new Mock<IControllerAssemblyProvider>();
controllerAssemblyProvider.SetupGet(x => x.CandidateAssemblies).Returns(_controllerAssemblies);
controllerAssemblyProvider.SetupGet(x => x.CandidateAssemblies).Returns(assemblies);
return new ReflectedActionDescriptorProvider(
controllerAssemblyProvider.Object,
actionDiscoveryConventions,
@ -206,6 +210,15 @@ namespace Microsoft.AspNet.Mvc.Test
private class CustomActionConvention : DefaultActionDiscoveryConventions
{
public override bool IsController([NotNull]TypeInfo typeInfo)
{
return
typeof(DefaultActionDiscoveryConventionsActionSelectionTests)
.GetNestedTypes(BindingFlags.NonPublic)
.Select(ct => ct.GetTypeInfo())
.Contains(typeInfo);
}
public override IEnumerable<string> GetSupportedHttpMethods(MethodInfo methodInfo)
{
if (methodInfo.Name.Equals("PostSomething", StringComparison.OrdinalIgnoreCase))
@ -217,8 +230,6 @@ namespace Microsoft.AspNet.Mvc.Test
}
}
#region Controller Classes
private class MixedRpcAndRestController
{
public void Index()
@ -304,8 +315,6 @@ namespace Microsoft.AspNet.Mvc.Test
public void Index(string s)
{ }
}
#endregion Controller Classes
}
}

View File

@ -0,0 +1,411 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Reflection;
using Microsoft.AspNet.Mvc.DefaultActionDiscoveryConventionsControllers;
using Xunit;
namespace Microsoft.AspNet.Mvc
{
public class DefaultActionDiscoveryConventionsTests
{
[Theory]
[InlineData("GetFromDerived", true)]
[InlineData("NewMethod", true)] // "NewMethod" is a public method declared with keyword "new".
[InlineData("GetFromBase", true)]
public void IsValidActionMethod_WithInheritedMethods(string methodName, bool expected)
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var method = typeof(DerivedController).GetMethod(methodName);
Assert.NotNull(method);
// Act
var isValid = conventions.IsValidActionMethod(method);
// Assert
Assert.Equal(expected, isValid);
}
[Fact]
public void IsValidActionMethod_OverridenMethodControllerClass()
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var method = typeof(BaseController).GetMethod("Redirect");
Assert.NotNull(method);
// Act
var isValid = conventions.IsValidActionMethod(method);
// Assert
Assert.False(isValid);
}
[Fact]
public void IsValidActionMethod_PrivateMethod_FromUserDefinedController()
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var method = typeof(DerivedController).GetMethod(
"PrivateMethod",
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
Assert.NotNull(method);
// Act
var isValid = conventions.IsValidActionMethod(method);
// Assert
Assert.False(isValid);
}
[Fact]
public void IsValidActionMethod_OperatorOverloadingMethod_FromOperatorOverloadingController()
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var method = typeof(OperatorOverloadingController).GetMethod("op_Addition");
Assert.NotNull(method);
Assert.True(method.IsSpecialName);
// Act
var isValid = conventions.IsValidActionMethod(method);
// Assert
Assert.False(isValid);
}
[Fact]
public void IsValidActionMethod_GenericMethod_FromUserDefinedController()
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var method = typeof(DerivedController).GetMethod("GenericMethod");
Assert.NotNull(method);
// Act
var isValid = conventions.IsValidActionMethod(method);
// Assert
Assert.False(isValid);
}
[Fact]
public void IsValidActionMethod_OverridenNonActionMethod()
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var method = typeof(DerivedController).GetMethod("OverridenNonActionMethod");
Assert.NotNull(method);
// Act
var isValid = conventions.IsValidActionMethod(method);
// Assert
Assert.False(isValid);
}
[Theory]
[InlineData("Equals")]
[InlineData("GetHashCode")]
[InlineData("MemberwiseClone")]
[InlineData("ToString")]
public void IsValidActionMethod_OverriddenMethodsFromObjectClass(string methodName)
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var method = typeof(DerivedController).GetMethod(
methodName,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
Assert.NotNull(method);
// Act
var isValid = conventions.IsValidActionMethod(method);
// Assert
Assert.False(isValid);
}
[Theory]
[InlineData("StaticMethod")]
[InlineData("ProtectedStaticMethod")]
[InlineData("PrivateStaticMethod")]
public void IsValidActionMethod_StaticMethods(string methodName)
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var method = typeof(DerivedController).GetMethod(
methodName,
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
Assert.NotNull(method);
// Act
var isValid = conventions.IsValidActionMethod(method);
// Assert
Assert.False(isValid);
}
[Fact]
public void IsController_UserDefinedClass()
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var typeInfo = typeof(BaseController).GetTypeInfo();
// Act
var isController = conventions.IsController(typeInfo);
// Assert
Assert.True(isController);
}
[Fact]
public void IsController_FrameworkControllerClass()
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var typeInfo = typeof(Controller).GetTypeInfo();
// Act
var isController = conventions.IsController(typeInfo);
// Assert
Assert.False(isController);
}
[Fact]
public void IsController_UserDefinedControllerClass()
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var typeInfo = typeof(DefaultActionDiscoveryConventionsControllers.Controller).GetTypeInfo();
// Act
var isController = conventions.IsController(typeInfo);
// Assert
Assert.False(isController);
}
[Fact]
public void IsController_Interface()
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var typeInfo = typeof(IController).GetTypeInfo();
// Act
var isController = conventions.IsController(typeInfo);
// Assert
Assert.False(isController);
}
[Fact]
public void IsController_AbstractClass()
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var typeInfo = typeof(AbstractController).GetTypeInfo();
// Act
var isController = conventions.IsController(typeInfo);
// Assert
Assert.False(isController);
}
[Fact]
public void IsController_DerivedAbstractClass()
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var typeInfo = typeof(DerivedAbstractController).GetTypeInfo();
// Act
var isController = conventions.IsController(typeInfo);
// Assert
Assert.True(isController);
}
[Fact]
public void IsController_OpenGenericClass()
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var typeInfo = typeof(OpenGenericController<>).GetTypeInfo();
// Act
var isController = conventions.IsController(typeInfo);
// Assert
Assert.False(isController);
}
[Fact]
public void IsController_ClosedGenericClass()
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var typeInfo = typeof(OpenGenericController<string>).GetTypeInfo();
// Act
var isController = conventions.IsController(typeInfo);
// Assert
Assert.False(isController);
}
[Fact]
public void IsController_DerivedGenericClass()
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var typeInfo = typeof(DerivedGenericController).GetTypeInfo();
// Act
var isController = conventions.IsController(typeInfo);
// Assert
Assert.True(isController);
}
[Fact]
public void IsController_Poco_WithNamingConvention()
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var typeInfo = typeof(PocoController).GetTypeInfo();
// Act
var isController = conventions.IsController(typeInfo);
// Assert
Assert.True(isController);
}
[Fact]
public void IsController_NoControllerSuffix()
{
// Arrange
var conventions = new DefaultActionDiscoveryConventions();
var typeInfo = typeof(NoSuffix).GetTypeInfo();
// Act
var isController = conventions.IsController(typeInfo);
// Assert
Assert.True(isController);
}
}
}
// 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.DefaultActionDiscoveryConventionsControllers
{
public abstract class AbstractController : Mvc.Controller
{
}
public class DerivedAbstractController : AbstractController
{
}
public class BaseController : Mvc.Controller
{
public void GetFromBase() // Valid action method.
{
}
[NonAction]
public virtual void OverridenNonActionMethod()
{
}
[NonAction]
public virtual void NewMethod()
{
}
public override RedirectResult Redirect(string url)
{
return base.Redirect(url + "#RedirectOverride");
}
}
public class DerivedController : BaseController
{
public void GetFromDerived() // Valid action method.
{
}
[HttpGet]
public override void OverridenNonActionMethod()
{
}
public new void NewMethod() // Valid action method.
{
}
public void GenericMethod<T>()
{
}
private void PrivateMethod()
{
}
public static void StaticMethod()
{
}
protected static void ProtectedStaticMethod()
{
}
private static void PrivateStaticMethod()
{
}
}
public class Controller
{
}
public class OpenGenericController<T>
{
}
public class DerivedGenericController : OpenGenericController<string>
{
}
public interface IController
{
}
public class NoSuffix : Mvc.Controller
{
}
public class PocoController
{
}
public class OperatorOverloadingController : Mvc.Controller
{
public static OperatorOverloadingController operator +(
OperatorOverloadingController c1,
OperatorOverloadingController c2)
{
return new OperatorOverloadingController();
}
}
}

View File

@ -28,9 +28,10 @@
<Compile Include="ActionResults\RedirectToActionResultTest.cs" />
<Compile Include="ActionResults\RedirectToRouteResultTest.cs" />
<Compile Include="ActionResults\RedirectResultTest.cs" />
<Compile Include="ActionSelectionConventionTests.cs" />
<Compile Include="DefaultActionDiscoveryConventionsActionSelectionTests.cs" />
<Compile Include="AntiXsrf\AntiForgeryOptionsTests.cs" />
<Compile Include="ExpiringFileInfoCacheTest.cs" />
<Compile Include="DefaultActionDiscoveryConventionsTests.cs" />
<Compile Include="Extensions\ViewEngineDscriptorExtensionsTest.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedParameterModelTests.cs" />
<Compile Include="ReflectedModelBuilder\ReflectedActionModelTests.cs" />
@ -74,6 +75,7 @@
<Compile Include="Rendering\DefaultViewEngineProviderTest.cs" />
<Compile Include="Routing\AttributeRoutePrecedenceTests.cs" />
<Compile Include="Routing\AttributeRouteTemplateTests.cs" />
<Compile Include="StaticControllerAssemblyProvider.cs" />
<Compile Include="TestController.cs" />
<Compile Include="TypeHelperTest.cs" />
<Compile Include="StaticActionDiscoveryConventions.cs" />
@ -82,4 +84,4 @@
<Compile Include="ViewComponentTests.cs" />
</ItemGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>
</Project>

View File

@ -14,117 +14,17 @@ namespace Microsoft.AspNet.Mvc.Test
public class ReflectedActionDescriptorProviderTests
{
[Fact]
public void GetDescriptors_GetsDescriptorsOnlyForValidActionsInBaseAndDerivedController()
{
// Arrange & Act
var actionNames = GetActionNamesFromDerivedController();
// Assert
// "NewMethod" is a public method declared with keyword "new".
Assert.Equal(new[] { "GetFromDerived", "NewMethod", "GetFromBase" }, actionNames);
}
[Fact]
public void GetDescriptors_Ignores_OverridenRedirect_FromControllerClass()
{
// Arrange & Act
var actionNames = GetDescriptors(typeof(BaseController).GetTypeInfo()).Select(a => a.Name);
// Assert
Assert.DoesNotContain("Redirect", actionNames);
}
[Fact]
public void GetDescriptors_Ignores_PrivateMethod_FromUserDefinedController()
{
// Arrange & Act
var actionNames = GetActionNamesFromDerivedController();
// Assert
Assert.DoesNotContain("PrivateMethod", actionNames);
}
[Fact]
public void GetDescriptors_Ignores_Constructor_FromUserDefinedController()
{
// Arrange & Act
var actionNames = GetActionNamesFromDerivedController();
// Assert
Assert.DoesNotContain("DerivedController", actionNames);
}
[Fact]
public void GetDescriptors_Ignores_OperatorOverloadingMethod_FromOperatorOverloadingController()
{
// Arrange & Act
var actionDescriptors = GetDescriptors(typeof(OperatorOverloadingController).GetTypeInfo());
// Assert
Assert.Empty(actionDescriptors);
}
[Fact]
public void GetDescriptors_Ignores_GenericMethod_FromUserDefinedController()
{
// Arrange & Act
var actionNames = GetActionNamesFromDerivedController();
// Assert
Assert.DoesNotContain("GenericMethod", actionNames);
}
[Fact]
public void GetDescriptors_Ignores_OverridenNonActionMethod_FromDerivedController()
{
// Arrange & Act
var actionNames = GetActionNamesFromDerivedController();
// Assert
Assert.DoesNotContain("OverridenNonActionMethod", actionNames);
}
[Fact]
public void GetDescriptors_Ignores_MethodsFromObjectClass_FromUserDefinedController()
public void GetDescriptors_GetsDescriptorsOnlyForValidActions()
{
// Arrange
var methodsFromObjectClass = typeof(object).GetMethods().Select(m => m.Name);
var provider = GetProvider(typeof(PersonController).GetTypeInfo());
// Act
var actionNames = GetActionNamesFromDerivedController();
var descriptors = provider.GetDescriptors();
var actionNames = descriptors.Select(ad => ad.Name);
// Assert
Assert.Empty(methodsFromObjectClass.Intersect(actionNames));
}
[Fact]
public void GetDescriptors_Ignores_StaticMethod_FromUserDefinedController()
{
// Arrange & Act
var actionNames = GetActionNamesFromDerivedController();
// Assert
Assert.DoesNotContain("StaticMethod", actionNames);
}
[Fact]
public void GetDescriptors_Ignores_ProtectedStaticMethod_FromUserDefinedController()
{
// Arrange & Act
var actionNames = GetActionNamesFromDerivedController();
// Assert
Assert.DoesNotContain("ProtectedStaticMethod", actionNames);
}
[Fact]
public void GetDescriptors_Ignores_PrivateStaticMethod_FromUserDefinedController()
{
// Arrange & Act
var actionNames = GetActionNamesFromDerivedController();
// Assert
Assert.DoesNotContain("PrivateStaticMethod", actionNames);
Assert.Equal(new[] { "GetPerson", "ListPeople", }, actionNames);
}
[Fact]
@ -276,7 +176,7 @@ namespace Microsoft.AspNet.Mvc.Test
{
// Arrange
var filter = new MyFilterAttribute(1);
var provider = GetProvider(typeof(BaseController).GetTypeInfo(), new IFilter[]
var provider = GetProvider(typeof(PersonController).GetTypeInfo(), new IFilter[]
{
filter,
});
@ -289,11 +189,6 @@ namespace Microsoft.AspNet.Mvc.Test
Assert.Same(filter, Assert.Single(filters));
}
private IEnumerable<string> GetActionNamesFromDerivedController()
{
return GetDescriptors(typeof(DerivedController).GetTypeInfo()).Select(a => a.Name).ToArray();
}
private ReflectedActionDescriptorProvider GetProvider(
TypeInfo controllerTypeInfo,
IEnumerable<IFilter> filters = null)
@ -334,93 +229,6 @@ namespace Microsoft.AspNet.Mvc.Test
return provider.GetDescriptors();
}
private class DerivedController : BaseController
{
public void GetFromDerived() // Valid action method.
{
}
[HttpGet]
public override void OverridenNonActionMethod()
{
}
public new void NewMethod() // Valid action method.
{
}
public void GenericMethod<T>()
{
}
private void PrivateMethod()
{
}
public static void StaticMethod()
{
}
protected static void ProtectedStaticMethod()
{
}
private static void PrivateStaticMethod()
{
}
}
private class OperatorOverloadingController : Controller
{
public static OperatorOverloadingController operator +(
OperatorOverloadingController c1,
OperatorOverloadingController c2)
{
return new OperatorOverloadingController();
}
}
private class BaseController : Controller
{
public void GetFromBase() // Valid action method.
{
}
[NonAction]
public virtual void OverridenNonActionMethod()
{
}
[NonAction]
public virtual void NewMethod()
{
}
public override RedirectResult Redirect(string url)
{
return base.Redirect(url + "#RedirectOverride");
}
}
[MyFilter(2)]
private class FiltersController
{
[MyFilter(3)]
public void FilterAction()
{
}
}
private class MyFilterAttribute : Attribute, IFilter
{
public MyFilterAttribute(int value)
{
Value = value;
}
public int Value { get; private set; }
}
private class HttpMethodController
{
[HttpPost]
@ -429,6 +237,27 @@ namespace Microsoft.AspNet.Mvc.Test
}
}
private class PersonController
{
public void GetPerson()
{ }
public void ListPeople()
{ }
[NonAction]
public void NotAnAction()
{ }
}
public class MyRouteConstraintAttribute : RouteConstraintAttribute
{
public MyRouteConstraintAttribute(bool blockNonAttributedActions)
: base("key", "value", blockNonAttributedActions)
{
}
}
[MyRouteConstraintAttribute(blockNonAttributedActions: true)]
private class BlockNonAttributedActionsController
{
@ -445,10 +274,21 @@ namespace Microsoft.AspNet.Mvc.Test
}
}
private class MyRouteConstraintAttribute : RouteConstraintAttribute
private class MyFilterAttribute : Attribute, IFilter
{
public MyRouteConstraintAttribute(bool blockNonAttributedActions)
: base("key", "value", blockNonAttributedActions)
public MyFilterAttribute(int value)
{
Value = value;
}
public int Value { get; private set; }
}
[MyFilter(2)]
private class FiltersController
{
[MyFilter(3)]
public void FilterAction()
{
}
}

View File

@ -0,0 +1,22 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Reflection;
namespace Microsoft.AspNet.Mvc.Test
{
/// <summary>
/// An implementation of IControllerAssemblyProvider that provides just this assembly.
/// </summary>
public class StaticControllerAssemblyProvider : IControllerAssemblyProvider
{
public IEnumerable<Assembly> CandidateAssemblies
{
get
{
yield return typeof(StaticActionDiscoveryConventions).GetTypeInfo().Assembly;
}
}
}
}