diff --git a/FluentSecurity.Specification/ConfigurationExpressionSpec.cs b/FluentSecurity.Specification/ConfigurationExpressionSpec.cs index 8e616c1f..aa9c41b2 100644 --- a/FluentSecurity.Specification/ConfigurationExpressionSpec.cs +++ b/FluentSecurity.Specification/ConfigurationExpressionSpec.cs @@ -141,6 +141,109 @@ public ActionResult ActualAction() } } + [TestFixture] + [Category("ConfigurationExpressionSpec")] + public class When_adding_a_policycontainter_for_void_action + { + [Test] + public void Should_have_policycontainer_for_controller_with_void_action() + { + // Arrange + var configurationExpression = new RootConfiguration(); + configurationExpression.GetAuthenticationStatusFrom(StaticHelper.IsAuthenticatedReturnsFalse); + + // Act + configurationExpression.For(x => x.VoidAction()); + + // Assert + Assert.That(configurationExpression.Runtime.PolicyContainers.Count(), Is.EqualTo(1)); + } + + [Test] + public void Should_have_policycontainer_for_void_action_from_parent_controller() + { + // Arrange + var configurationExpression = new RootConfiguration(); + configurationExpression.GetAuthenticationStatusFrom(StaticHelper.IsAuthenticatedReturnsFalse); + + // Act + configurationExpression.For(x => x.VoidAction()); + + // Assert + Assert.That(configurationExpression.Runtime.PolicyContainers.Count(), Is.EqualTo(1)); + } + + private class ParentVoidActionController : Controller + { + public void VoidAction() + { + + } + } + + private class ChildVoidActionController:ParentVoidActionController + { + + } + } + + [Category("ConfigurationExpressionSpec")] + public class When_adding_a_policycontainter_using_ByController_convention + { + [Test] + public void Should_have_policycontainer_for_all_actions_including_void_actions() + { + // Arrange + var configurationExpression = new RootConfiguration(); + configurationExpression.GetAuthenticationStatusFrom(StaticHelper.IsAuthenticatedReturnsFalse); + + // Act + configurationExpression.For(); + + // Assert + Assert.That(configurationExpression.Runtime.PolicyContainers.Count(), Is.EqualTo(2)); + } + + public void Should_have_policycontainer_for_all_actions_including_inherited_void_actions() + { + // Arrange + var configurationExpression = new RootConfiguration(); + configurationExpression.GetAuthenticationStatusFrom(StaticHelper.IsAuthenticatedReturnsFalse); + + // Act + configurationExpression.For(); + + // Assert + Assert.That(configurationExpression.Runtime.PolicyContainers.Count(), Is.EqualTo(2)); + } + + private class ParentVoidActionController : Controller + { + public void VoidAction() + { + + } + + public ActionResult DummyAction() + { + return new EmptyResult(); + } + } + + private class ChildVoidActionController : ParentVoidActionController + { + public void VoidAction() + { + + } + + public ActionResult DummyAction() + { + return new EmptyResult(); + } + } + } + [TestFixture] [Category("ConfigurationExpressionSpec")] public class When_adding_a_policycontainter_for_Blog_Index_and_AddPost diff --git a/FluentSecurity/ConfigurationExpression.cs b/FluentSecurity/ConfigurationExpression.cs index afd9d86f..3d420984 100644 --- a/FluentSecurity/ConfigurationExpression.cs +++ b/FluentSecurity/ConfigurationExpression.cs @@ -39,6 +39,14 @@ internal void Initialize(SecurityRuntime runtime) return AddPolicyContainerFor(controllerName, actionName); } + public IPolicyContainerConfiguration For(Expression> actionExpression) where TController : Controller + { + var controllerName = typeof(TController).GetControllerName(); + var actionName = actionExpression.GetActionName(); + + return AddPolicyContainerFor(controllerName, actionName); + } + public IPolicyContainerConfiguration For() where TController : Controller { var controllerType = typeof(TController); diff --git a/FluentSecurity/Extensions.cs b/FluentSecurity/Extensions.cs index b1d768eb..87128b51 100644 --- a/FluentSecurity/Extensions.cs +++ b/FluentSecurity/Extensions.cs @@ -80,13 +80,32 @@ internal static IEnumerable GetActionMethods(this Type controllerTyp return controllerType .GetMethods( BindingFlags.Public | - BindingFlags.Instance + BindingFlags.Instance ) - .Where(methodInfo => methodInfo.ReturnType.IsControllerActionReturnType()) + .Where(IsValidActionMethod) .Where(action => actionFilter.Invoke(new ControllerActionInfo(controllerType, action))) .ToList(); } + internal static bool IsValidActionMethod(this MethodInfo methodInfo) + { + return methodInfo.ReturnType.IsControllerActionReturnType() && + !methodInfo.IsSpecialName && !methodInfo.IsDeclaredBy(); + } + + /// + /// Returns true if the passed method is declared by the type T. + /// + /// + /// + //(Chandu) The method below is to simulate the way System.Web.Mvc.ActionMethodSelector.IsValidActionMethod identifies methods of a controller as valid actions + internal static bool IsDeclaredBy(this MethodInfo methodInfo) + { + var passedType = typeof (T); + var declaringType = methodInfo.GetBaseDefinition().DeclaringType; + return declaringType != null && declaringType.IsAssignableFrom(passedType); + } + /// /// Returns true if the type matches a controller action return type. /// @@ -94,7 +113,12 @@ internal static IEnumerable GetActionMethods(this Type controllerTyp /// internal static bool IsControllerActionReturnType(this Type returnType) { - return typeof (ActionResult).IsAssignableFrom(returnType) || typeof (Task).IsAssignableFromGenericType(returnType); + return + ( + typeof (ActionResult).IsAssignableFrom(returnType) || + typeof (Task).IsAssignableFromGenericType(returnType) || + typeof(void).IsAssignableFrom(returnType) + ); } ///