You've already forked linux-packaging-mono
Rewrite with hard-coded offsets into the PE file format to discern if a binary is PE32 or PE32+, and then to determine if it contains a "CLR Data Directory" entry that looks valid. Tested with PE32 and PE32+ compiled Mono binaries, PE32 and PE32+ native binaries, and a random assortment of garbage files. Former-commit-id: 9e7ac86ec84f653a2f79b87183efd5b0ebda001b
2430 lines
104 KiB
C#
2430 lines
104 KiB
C#
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Threading;
|
|
using Microsoft.Web.UnitTestUtil;
|
|
using Moq;
|
|
using Xunit;
|
|
using Assert = Microsoft.TestCommon.AssertEx;
|
|
|
|
namespace System.Web.Mvc.Test
|
|
{
|
|
[CLSCompliant(false)]
|
|
public class ControllerActionInvokerTest
|
|
{
|
|
[Fact]
|
|
public void CreateActionResultWithActionResultParameterReturnsParameterUnchanged()
|
|
{
|
|
// Arrange
|
|
ControllerActionInvokerHelper invoker = new ControllerActionInvokerHelper();
|
|
ActionResult originalResult = new JsonResult();
|
|
|
|
// Act
|
|
ActionResult returnedActionResult = invoker.PublicCreateActionResult(null, null, originalResult);
|
|
|
|
// Assert
|
|
Assert.Same(originalResult, returnedActionResult);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateActionResultWithNullParameterReturnsEmptyResult()
|
|
{
|
|
// Arrange
|
|
ControllerActionInvokerHelper invoker = new ControllerActionInvokerHelper();
|
|
|
|
// Act
|
|
ActionResult returnedActionResult = invoker.PublicCreateActionResult(null, null, null);
|
|
|
|
// Assert
|
|
Assert.IsType<EmptyResult>(returnedActionResult);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateActionResultWithObjectParameterReturnsContentResult()
|
|
{
|
|
// Arrange
|
|
ControllerActionInvokerHelper invoker = new ControllerActionInvokerHelper();
|
|
object originalReturnValue = new CultureReflector();
|
|
|
|
// Act
|
|
ActionResult returnedActionResult = invoker.PublicCreateActionResult(null, null, originalReturnValue);
|
|
|
|
// Assert
|
|
ContentResult contentResult = Assert.IsType<ContentResult>(returnedActionResult);
|
|
Assert.Equal("ivl", contentResult.Content);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindAction()
|
|
{
|
|
// Arrange
|
|
EmptyController controller = new EmptyController();
|
|
ControllerContext controllerContext = GetControllerContext(controller);
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
ActionDescriptor expectedAd = new Mock<ActionDescriptor>().Object;
|
|
Mock<ControllerDescriptor> mockCd = new Mock<ControllerDescriptor>();
|
|
mockCd.Setup(cd => cd.FindAction(controllerContext, "someAction")).Returns(expectedAd);
|
|
|
|
// Act
|
|
ActionDescriptor returnedAd = helper.PublicFindAction(controllerContext, mockCd.Object, "someAction");
|
|
|
|
// Assert
|
|
Assert.Equal(expectedAd, returnedAd);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindActionDoesNotMatchConstructor()
|
|
{
|
|
// FindActionMethod() shouldn't match special-named methods like type constructors.
|
|
|
|
// Arrange
|
|
Controller controller = new FindMethodController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new ReflectedControllerDescriptor(typeof(FindMethodController));
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
// Act
|
|
ActionDescriptor ad = helper.PublicFindAction(context, cd, ".ctor");
|
|
ActionDescriptor ad2 = helper.PublicFindAction(context, cd, "FindMethodController");
|
|
|
|
// Assert
|
|
Assert.Null(ad);
|
|
Assert.Null(ad2);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindActionDoesNotMatchEvent()
|
|
{
|
|
// FindActionMethod() should skip methods that aren't publicly visible.
|
|
|
|
// Arrange
|
|
Controller controller = new FindMethodController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new ReflectedControllerDescriptor(typeof(FindMethodController));
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
// Act
|
|
ActionDescriptor ad = helper.PublicFindAction(context, cd, "add_Event");
|
|
|
|
// Assert
|
|
Assert.Null(ad);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindActionDoesNotMatchInternalMethod()
|
|
{
|
|
// FindActionMethod() should skip methods that aren't publicly visible.
|
|
|
|
// Arrange
|
|
Controller controller = new FindMethodController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new ReflectedControllerDescriptor(typeof(FindMethodController));
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
// Act
|
|
ActionDescriptor ad = helper.PublicFindAction(context, cd, "InternalMethod");
|
|
|
|
// Assert
|
|
Assert.Null(ad);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindActionDoesNotMatchMethodsDefinedOnControllerType()
|
|
{
|
|
// FindActionMethod() shouldn't match methods originally defined on the Controller type, e.g. Dispose().
|
|
|
|
// Arrange
|
|
Controller controller = new BlankController();
|
|
ControllerDescriptor cd = new ReflectedControllerDescriptor(typeof(BlankController));
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
var methods = typeof(Controller).GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
|
|
|
// Act & Assert
|
|
foreach (var method in methods)
|
|
{
|
|
bool wasFound = true;
|
|
try
|
|
{
|
|
ActionDescriptor ad = helper.PublicFindAction(context, cd, method.Name);
|
|
wasFound = (ad != null);
|
|
}
|
|
finally
|
|
{
|
|
Assert.False(wasFound, "FindAction() should return false for methods defined on the Controller class: " + method);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void FindActionDoesNotMatchMethodsDefinedOnObjectType()
|
|
{
|
|
// FindActionMethod() shouldn't match methods originally defined on the Object type, e.g. ToString().
|
|
|
|
// Arrange
|
|
Controller controller = new FindMethodController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new ReflectedControllerDescriptor(typeof(FindMethodController));
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
// Act
|
|
ActionDescriptor ad = helper.PublicFindAction(context, cd, "ToString");
|
|
|
|
// Assert
|
|
Assert.Null(ad);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindActionDoesNotMatchNonActionMethod()
|
|
{
|
|
// FindActionMethod() should respect the [NonAction] attribute.
|
|
|
|
// Arrange
|
|
Controller controller = new FindMethodController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new ReflectedControllerDescriptor(typeof(FindMethodController));
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
// Act
|
|
ActionDescriptor ad = helper.PublicFindAction(context, cd, "NonActionMethod");
|
|
|
|
// Assert
|
|
Assert.Null(ad);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindActionDoesNotMatchOverriddenNonActionMethod()
|
|
{
|
|
// FindActionMethod() should trace the method's inheritance chain looking for the [NonAction] attribute.
|
|
|
|
// Arrange
|
|
Controller controller = new DerivedFindMethodController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new ReflectedControllerDescriptor(typeof(DerivedFindMethodController));
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
// Act
|
|
ActionDescriptor ad = helper.PublicFindAction(context, cd, "InternalMethod");
|
|
|
|
// Assert
|
|
Assert.Null(ad);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindActionDoesNotMatchPrivateMethod()
|
|
{
|
|
// FindActionMethod() should skip methods that aren't publicly visible.
|
|
|
|
// Arrange
|
|
Controller controller = new FindMethodController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new ReflectedControllerDescriptor(typeof(FindMethodController));
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
// Act
|
|
ActionDescriptor ad = helper.PublicFindAction(context, cd, "PrivateMethod");
|
|
|
|
// Assert
|
|
Assert.Null(ad);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindActionDoesNotMatchProperty()
|
|
{
|
|
// FindActionMethod() shouldn't match special-named methods like property getters.
|
|
|
|
// Arrange
|
|
Controller controller = new FindMethodController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new ReflectedControllerDescriptor(typeof(FindMethodController));
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
// Act
|
|
ActionDescriptor ad = helper.PublicFindAction(context, cd, "get_Property");
|
|
|
|
// Assert
|
|
Assert.Null(ad);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindActionDoesNotMatchProtectedMethod()
|
|
{
|
|
// FindActionMethod() should skip methods that aren't publicly visible.
|
|
|
|
// Arrange
|
|
Controller controller = new FindMethodController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new ReflectedControllerDescriptor(typeof(FindMethodController));
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
// Act
|
|
ActionDescriptor ad = helper.PublicFindAction(context, cd, "ProtectedMethod");
|
|
|
|
// Assert
|
|
Assert.Null(ad);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindActionIsCaseInsensitive()
|
|
{
|
|
// Arrange
|
|
Controller controller = new FindMethodController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new ReflectedControllerDescriptor(typeof(FindMethodController));
|
|
MethodInfo expectedMethodInfo = typeof(FindMethodController).GetMethod("ValidActionMethod");
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
// Act
|
|
ActionDescriptor ad1 = helper.PublicFindAction(context, cd, "validactionmethod");
|
|
ActionDescriptor ad2 = helper.PublicFindAction(context, cd, "VALIDACTIONMETHOD");
|
|
|
|
// Assert
|
|
ReflectedActionDescriptor rad1 = Assert.IsType<ReflectedActionDescriptor>(ad1);
|
|
Assert.Same(expectedMethodInfo, rad1.MethodInfo);
|
|
ReflectedActionDescriptor rad2 = Assert.IsType<ReflectedActionDescriptor>(ad2);
|
|
Assert.Same(expectedMethodInfo, rad2.MethodInfo);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindActionMatchesActionMethodWithClosedGenerics()
|
|
{
|
|
// FindActionMethod() should work with generic methods as long as there are no open types.
|
|
|
|
// Arrange
|
|
Controller controller = new GenericFindMethodController<int>();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new ReflectedControllerDescriptor(typeof(GenericFindMethodController<int>));
|
|
MethodInfo expectedMethodInfo = typeof(GenericFindMethodController<int>).GetMethod("ClosedGenericMethod");
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
// Act
|
|
ActionDescriptor ad = helper.PublicFindAction(context, cd, "ClosedGenericMethod");
|
|
|
|
// Assert
|
|
ReflectedActionDescriptor rad = Assert.IsType<ReflectedActionDescriptor>(ad);
|
|
Assert.Same(expectedMethodInfo, rad.MethodInfo);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindActionMatchesNewActionMethodsHidingNonActionMethods()
|
|
{
|
|
// FindActionMethod() should stop looking for [NonAction] in the method's inheritance chain when it sees
|
|
// that a method in a derived class hides the a method in the base class.
|
|
|
|
// Arrange
|
|
Controller controller = new DerivedFindMethodController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new ReflectedControllerDescriptor(typeof(DerivedFindMethodController));
|
|
MethodInfo expectedMethodInfo = typeof(DerivedFindMethodController).GetMethod("DerivedIsActionMethod");
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
// Act
|
|
ActionDescriptor ad = helper.PublicFindAction(context, cd, "DerivedIsActionMethod");
|
|
|
|
// Assert
|
|
ReflectedActionDescriptor rad = Assert.IsType<ReflectedActionDescriptor>(ad);
|
|
Assert.Same(expectedMethodInfo, rad.MethodInfo);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetControllerDescriptor()
|
|
{
|
|
// Arrange
|
|
EmptyController controller = new EmptyController();
|
|
ControllerContext controllerContext = GetControllerContext(controller);
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
// Act
|
|
ControllerDescriptor cd = helper.PublicGetControllerDescriptor(controllerContext);
|
|
|
|
// Assert
|
|
Assert.IsType<ReflectedControllerDescriptor>(cd);
|
|
Assert.Equal(typeof(EmptyController), cd.ControllerType);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetFiltersSplitsFilterObjectsIntoFilterInfo()
|
|
{
|
|
// Arrange
|
|
IActionFilter actionFilter = new Mock<IActionFilter>().Object;
|
|
IResultFilter resultFilter = new Mock<IResultFilter>().Object;
|
|
IAuthorizationFilter authFilter = new Mock<IAuthorizationFilter>().Object;
|
|
IExceptionFilter exFilter = new Mock<IExceptionFilter>().Object;
|
|
object noneOfTheAbove = new object();
|
|
ControllerActionInvokerHelper invoker = new ControllerActionInvokerHelper(actionFilter, authFilter, exFilter, resultFilter, noneOfTheAbove);
|
|
ControllerContext context = new ControllerContext();
|
|
ActionDescriptor descriptor = new Mock<ActionDescriptor>().Object;
|
|
|
|
// Act
|
|
FilterInfo result = invoker.PublicGetFilters(context, descriptor);
|
|
|
|
// Assert
|
|
Assert.Same(actionFilter, result.ActionFilters.Single());
|
|
Assert.Same(authFilter, result.AuthorizationFilters.Single());
|
|
Assert.Same(exFilter, result.ExceptionFilters.Single());
|
|
Assert.Same(resultFilter, result.ResultFilters.Single());
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterValueAllowsAllSubpropertiesIfBindAttributeNotSpecified()
|
|
{
|
|
// Arrange
|
|
CustomConverterController controller = new CustomConverterController();
|
|
ControllerContext controllerContext = GetControllerContext(controller);
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
ParameterInfo paramWithoutBindAttribute = typeof(CustomConverterController).GetMethod("ParameterWithoutBindAttribute").GetParameters()[0];
|
|
ReflectedParameterDescriptor pd = new ReflectedParameterDescriptor(paramWithoutBindAttribute, new Mock<ActionDescriptor>().Object);
|
|
|
|
// Act
|
|
object valueWithoutBindAttribute = helper.PublicGetParameterValue(controllerContext, pd);
|
|
|
|
// Assert
|
|
Assert.Equal("foo=True&bar=True", valueWithoutBindAttribute);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterValueResolvesConvertersInCorrectOrderOfPrecedence()
|
|
{
|
|
// Order of precedence:
|
|
// 1. Attributes on the parameter itself
|
|
// 2. Query the global converter provider
|
|
|
|
// Arrange
|
|
CustomConverterController controller = new CustomConverterController();
|
|
Dictionary<string, object> values = new Dictionary<string, object> { { "foo", "fooValue" } };
|
|
ControllerContext controllerContext = GetControllerContext(controller, values);
|
|
controller.ControllerContext = controllerContext;
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
ParameterInfo paramWithOneConverter = typeof(CustomConverterController).GetMethod("ParameterHasOneConverter").GetParameters()[0];
|
|
ReflectedParameterDescriptor pdOneConverter = new ReflectedParameterDescriptor(paramWithOneConverter, new Mock<ActionDescriptor>().Object);
|
|
ParameterInfo paramWithNoConverters = typeof(CustomConverterController).GetMethod("ParameterHasNoConverters").GetParameters()[0];
|
|
ReflectedParameterDescriptor pdNoConverters = new ReflectedParameterDescriptor(paramWithNoConverters, new Mock<ActionDescriptor>().Object);
|
|
|
|
// Act
|
|
object valueWithOneConverter = helper.PublicGetParameterValue(controllerContext, pdOneConverter);
|
|
object valueWithNoConverters = helper.PublicGetParameterValue(controllerContext, pdNoConverters);
|
|
|
|
// Assert
|
|
Assert.Equal("foo_String", valueWithOneConverter);
|
|
Assert.Equal("fooValue", valueWithNoConverters);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterValueRespectsBindAttribute()
|
|
{
|
|
// Arrange
|
|
CustomConverterController controller = new CustomConverterController();
|
|
ControllerContext controllerContext = GetControllerContext(controller);
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
ParameterInfo paramWithBindAttribute = typeof(CustomConverterController).GetMethod("ParameterHasBindAttribute").GetParameters()[0];
|
|
ReflectedParameterDescriptor pd = new ReflectedParameterDescriptor(paramWithBindAttribute, new Mock<ActionDescriptor>().Object);
|
|
|
|
// Act
|
|
object valueWithBindAttribute = helper.PublicGetParameterValue(controllerContext, pd);
|
|
|
|
// Assert
|
|
Assert.Equal("foo=True&bar=False", valueWithBindAttribute);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterValueRespectsBindAttributePrefix()
|
|
{
|
|
// Arrange
|
|
CustomConverterController controller = new CustomConverterController();
|
|
Dictionary<string, object> values = new Dictionary<string, object> { { "foo", "fooValue" }, { "bar", "barValue" } };
|
|
ControllerContext controllerContext = GetControllerContext(controller, values);
|
|
controller.ControllerContext = controllerContext;
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
ParameterInfo paramWithFieldPrefix = typeof(CustomConverterController).GetMethod("ParameterHasFieldPrefix").GetParameters()[0];
|
|
ReflectedParameterDescriptor pd = new ReflectedParameterDescriptor(paramWithFieldPrefix, new Mock<ActionDescriptor>().Object);
|
|
|
|
// Act
|
|
object parameterValue = helper.PublicGetParameterValue(controllerContext, pd);
|
|
|
|
// Assert
|
|
Assert.Equal("barValue", parameterValue);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterValueRespectsBindAttributePrefixOnComplexType()
|
|
{
|
|
// Arrange
|
|
CustomConverterController controller = new CustomConverterController();
|
|
Dictionary<string, object> values = new Dictionary<string, object> { { "intprop", "123" }, { "stringprop", "hello" } };
|
|
ControllerContext controllerContext = GetControllerContext(controller, values);
|
|
controller.ControllerContext = controllerContext;
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
ParameterInfo paramWithFieldPrefix = typeof(CustomConverterController).GetMethod("ParameterHasPrefixAndComplexType").GetParameters()[0];
|
|
ReflectedParameterDescriptor pd = new ReflectedParameterDescriptor(paramWithFieldPrefix, new Mock<ActionDescriptor>().Object);
|
|
|
|
// Act
|
|
MySimpleModel parameterValue = helper.PublicGetParameterValue(controllerContext, pd) as MySimpleModel;
|
|
|
|
// Assert
|
|
Assert.Null(parameterValue);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterValueRespectsBindAttributeNullPrefix()
|
|
{
|
|
// Arrange
|
|
CustomConverterController controller = new CustomConverterController();
|
|
Dictionary<string, object> values = new Dictionary<string, object> { { "foo", "fooValue" }, { "bar", "barValue" } };
|
|
ControllerContext controllerContext = GetControllerContext(controller, values);
|
|
controller.ControllerContext = controllerContext;
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
ParameterInfo paramWithFieldPrefix = typeof(CustomConverterController).GetMethod("ParameterHasNullFieldPrefix").GetParameters()[0];
|
|
ReflectedParameterDescriptor pd = new ReflectedParameterDescriptor(paramWithFieldPrefix, new Mock<ActionDescriptor>().Object);
|
|
|
|
// Act
|
|
object parameterValue = helper.PublicGetParameterValue(controllerContext, pd);
|
|
|
|
// Assert
|
|
Assert.Equal("fooValue", parameterValue);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterValueRespectsBindAttributeNullPrefixOnComplexType()
|
|
{
|
|
// Arrange
|
|
CustomConverterController controller = new CustomConverterController();
|
|
Dictionary<string, object> values = new Dictionary<string, object> { { "intprop", "123" }, { "stringprop", "hello" } };
|
|
ControllerContext controllerContext = GetControllerContext(controller, values);
|
|
controller.ControllerContext = controllerContext;
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
ParameterInfo paramWithFieldPrefix = typeof(CustomConverterController).GetMethod("ParameterHasNoPrefixAndComplexType").GetParameters()[0];
|
|
ReflectedParameterDescriptor pd = new ReflectedParameterDescriptor(paramWithFieldPrefix, new Mock<ActionDescriptor>().Object);
|
|
|
|
// Act
|
|
MySimpleModel parameterValue = helper.PublicGetParameterValue(controllerContext, pd) as MySimpleModel;
|
|
|
|
// Assert
|
|
Assert.NotNull(parameterValue);
|
|
Assert.Equal(123, parameterValue.IntProp);
|
|
Assert.Equal("hello", parameterValue.StringProp);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterValueRespectsBindAttributeEmptyPrefix()
|
|
{
|
|
// Arrange
|
|
CustomConverterController controller = new CustomConverterController();
|
|
Dictionary<string, object> values = new Dictionary<string, object> { { "foo", "fooValue" }, { "bar", "barValue" }, { "intprop", "123" }, { "stringprop", "hello" } };
|
|
ControllerContext controllerContext = GetControllerContext(controller, values);
|
|
controller.ControllerContext = controllerContext;
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
ParameterInfo paramWithFieldPrefix = typeof(CustomConverterController).GetMethod("ParameterHasEmptyFieldPrefix").GetParameters()[0];
|
|
ReflectedParameterDescriptor pd = new ReflectedParameterDescriptor(paramWithFieldPrefix, new Mock<ActionDescriptor>().Object);
|
|
|
|
// Act
|
|
MySimpleModel parameterValue = helper.PublicGetParameterValue(controllerContext, pd) as MySimpleModel;
|
|
|
|
// Assert
|
|
Assert.NotNull(parameterValue);
|
|
Assert.Equal(123, parameterValue.IntProp);
|
|
Assert.Equal("hello", parameterValue.StringProp);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterValueRespectsDefaultValueAttribute()
|
|
{
|
|
// Arrange
|
|
CustomConverterController controller = new CustomConverterController();
|
|
ControllerContext controllerContext = GetControllerContext(controller);
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
controller.ValueProvider = new SimpleValueProvider();
|
|
|
|
ParameterInfo paramWithDefaultValueAttribute = typeof(CustomConverterController).GetMethod("ParameterHasDefaultValueAttribute").GetParameters()[0];
|
|
ReflectedParameterDescriptor pd = new ReflectedParameterDescriptor(paramWithDefaultValueAttribute, new Mock<ActionDescriptor>().Object);
|
|
|
|
// Act
|
|
object valueWithDefaultValueAttribute = helper.PublicGetParameterValue(controllerContext, pd);
|
|
|
|
// Assert
|
|
Assert.Equal(42, valueWithDefaultValueAttribute);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterValueReturnsNullIfCannotConvertNonRequiredParameter()
|
|
{
|
|
// Arrange
|
|
Dictionary<string, object> dict = new Dictionary<string, object>()
|
|
{
|
|
{ "id", DateTime.Now } // cannot convert DateTime to Nullable<int>
|
|
};
|
|
var controller = new ParameterTestingController();
|
|
ControllerContext context = GetControllerContext(controller, dict);
|
|
controller.ControllerContext = context;
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
MethodInfo mi = typeof(ParameterTestingController).GetMethod("TakesNullableInt");
|
|
ParameterInfo[] pis = mi.GetParameters();
|
|
ReflectedParameterDescriptor pd = new ReflectedParameterDescriptor(pis[0], new Mock<ActionDescriptor>().Object);
|
|
|
|
// Act
|
|
object oValue = helper.PublicGetParameterValue(context, pd);
|
|
|
|
// Assert
|
|
Assert.Null(oValue);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterValueReturnsNullIfNullableTypeValueNotFound()
|
|
{
|
|
// Arrange
|
|
var controller = new ParameterTestingController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
controller.ControllerContext = context;
|
|
controller.ValueProvider = new SimpleValueProvider();
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
MethodInfo mi = typeof(ParameterTestingController).GetMethod("TakesNullableInt");
|
|
ParameterInfo[] pis = mi.GetParameters();
|
|
ReflectedParameterDescriptor pd = new ReflectedParameterDescriptor(pis[0], new Mock<ActionDescriptor>().Object);
|
|
|
|
// Act
|
|
object oValue = helper.PublicGetParameterValue(context, pd);
|
|
|
|
// Assert
|
|
Assert.Null(oValue);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterValueReturnsNullIfReferenceTypeValueNotFound()
|
|
{
|
|
// Arrange
|
|
var controller = new ParameterTestingController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
controller.ControllerContext = context;
|
|
controller.ValueProvider = new SimpleValueProvider();
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
MethodInfo mi = typeof(ParameterTestingController).GetMethod("Foo");
|
|
ParameterInfo[] pis = mi.GetParameters();
|
|
ReflectedParameterDescriptor pd = new ReflectedParameterDescriptor(pis[0], new Mock<ActionDescriptor>().Object);
|
|
|
|
// Act
|
|
object oValue = helper.PublicGetParameterValue(context, pd);
|
|
|
|
// Assert
|
|
Assert.Null(oValue);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterValuesCallsGetParameterValue()
|
|
{
|
|
// Arrange
|
|
ControllerBase controller = new ParameterTestingController();
|
|
IDictionary<string, object> dict = new Dictionary<string, object>();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
MethodInfo mi = typeof(ParameterTestingController).GetMethod("Foo");
|
|
ReflectedActionDescriptor ad = new ReflectedActionDescriptor(mi, "Foo", new Mock<ControllerDescriptor>().Object);
|
|
ParameterDescriptor[] pds = ad.GetParameters();
|
|
|
|
Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>() { CallBase = true };
|
|
mockHelper.Setup(h => h.PublicGetParameterValue(context, pds[0])).Returns("Myfoo").Verifiable();
|
|
mockHelper.Setup(h => h.PublicGetParameterValue(context, pds[1])).Returns("Mybar").Verifiable();
|
|
mockHelper.Setup(h => h.PublicGetParameterValue(context, pds[2])).Returns("Mybaz").Verifiable();
|
|
ControllerActionInvokerHelper helper = mockHelper.Object;
|
|
|
|
// Act
|
|
IDictionary<string, object> parameters = helper.PublicGetParameterValues(context, ad);
|
|
|
|
// Assert
|
|
Assert.Equal(3, parameters.Count);
|
|
Assert.Equal("Myfoo", parameters["foo"]);
|
|
Assert.Equal("Mybar", parameters["bar"]);
|
|
Assert.Equal("Mybaz", parameters["baz"]);
|
|
mockHelper.Verify();
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterValuesReturnsEmptyDictionaryForParameterlessMethod()
|
|
{
|
|
// Arrange
|
|
var controller = new ParameterTestingController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
MethodInfo mi = typeof(ParameterTestingController).GetMethod("Parameterless");
|
|
ReflectedActionDescriptor ad = new ReflectedActionDescriptor(mi, "Parameterless", new Mock<ControllerDescriptor>().Object);
|
|
|
|
// Act
|
|
IDictionary<string, object> parameters = helper.PublicGetParameterValues(context, ad);
|
|
|
|
// Assert
|
|
Assert.Empty(parameters);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterValuesReturnsValuesForParametersInOrder()
|
|
{
|
|
// We need to hook into GetParameterValue() to make sure that GetParameterValues() is calling it.
|
|
|
|
// Arrange
|
|
var controller = new ParameterTestingController();
|
|
Dictionary<string, object> dict = new Dictionary<string, object>()
|
|
{
|
|
{ "foo", "MyFoo" },
|
|
{ "bar", "MyBar" },
|
|
{ "baz", "MyBaz" }
|
|
};
|
|
ControllerContext context = GetControllerContext(controller, dict);
|
|
controller.ControllerContext = context;
|
|
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
MethodInfo mi = typeof(ParameterTestingController).GetMethod("Foo");
|
|
ReflectedActionDescriptor ad = new ReflectedActionDescriptor(mi, "Foo", new Mock<ControllerDescriptor>().Object);
|
|
|
|
// Act
|
|
IDictionary<string, object> parameters = helper.PublicGetParameterValues(context, ad);
|
|
|
|
// Assert
|
|
Assert.Equal(3, parameters.Count);
|
|
Assert.Equal("MyFoo", parameters["foo"]);
|
|
Assert.Equal("MyBar", parameters["bar"]);
|
|
Assert.Equal("MyBaz", parameters["baz"]);
|
|
}
|
|
|
|
[Fact]
|
|
public void GetParameterValueUsesControllerValueProviderAsValueProvider()
|
|
{
|
|
// Arrange
|
|
Dictionary<string, object> values = new Dictionary<string, object>()
|
|
{
|
|
{ "foo", "fooValue" }
|
|
};
|
|
|
|
CustomConverterController controller = new CustomConverterController();
|
|
ControllerContext controllerContext = GetControllerContext(controller, values);
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
ParameterInfo parameter = typeof(CustomConverterController).GetMethod("ParameterHasNoConverters").GetParameters()[0];
|
|
ReflectedParameterDescriptor pd = new ReflectedParameterDescriptor(parameter, new Mock<ActionDescriptor>().Object);
|
|
|
|
// Act
|
|
object parameterValue = helper.PublicGetParameterValue(controllerContext, pd);
|
|
|
|
// Assert
|
|
Assert.Equal("fooValue", parameterValue);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeAction()
|
|
{
|
|
// Arrange
|
|
ControllerBase controller = new Mock<ControllerBase>().Object;
|
|
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new Mock<ControllerDescriptor>().Object;
|
|
ActionDescriptor ad = new Mock<ActionDescriptor>().Object;
|
|
FilterInfo filterInfo = new FilterInfo();
|
|
|
|
IDictionary<string, object> parameters = new Dictionary<string, object>();
|
|
MethodInfo methodInfo = typeof(object).GetMethod("ToString");
|
|
ActionResult actionResult = new EmptyResult();
|
|
ActionExecutedContext postContext = new ActionExecutedContext(context, ad, false /* canceled */, null /* exception */)
|
|
{
|
|
Result = actionResult
|
|
};
|
|
AuthorizationContext authContext = new AuthorizationContext();
|
|
|
|
Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>() { CallBase = true };
|
|
mockHelper.Setup(h => h.PublicGetControllerDescriptor(context)).Returns(cd).Verifiable();
|
|
mockHelper.Setup(h => h.PublicFindAction(context, cd, "SomeMethod")).Returns(ad).Verifiable();
|
|
mockHelper.Setup(h => h.PublicGetFilters(context, ad)).Returns(filterInfo).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeAuthorizationFilters(context, filterInfo.AuthorizationFilters, ad)).Returns(authContext).Verifiable();
|
|
mockHelper.Setup(h => h.PublicGetParameterValues(context, ad)).Returns(parameters).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeActionMethodWithFilters(context, filterInfo.ActionFilters, ad, parameters)).Returns(postContext).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeActionResultWithFilters(context, filterInfo.ResultFilters, actionResult)).Returns((ResultExecutedContext)null).Verifiable();
|
|
ControllerActionInvokerHelper helper = mockHelper.Object;
|
|
|
|
// Act
|
|
bool retVal = helper.InvokeAction(context, "SomeMethod");
|
|
Assert.True(retVal);
|
|
mockHelper.Verify();
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionCallsValidateRequestIfAsked()
|
|
{
|
|
// Arrange
|
|
ControllerBase controller = new Mock<ControllerBase>().Object;
|
|
controller.ValidateRequest = true;
|
|
bool validateInputWasCalled = false;
|
|
|
|
ControllerContext context = GetControllerContext(controller, null, validateInputCallback: () => { validateInputWasCalled = true; });
|
|
ControllerDescriptor cd = new Mock<ControllerDescriptor>().Object;
|
|
ActionDescriptor ad = new Mock<ActionDescriptor>().Object;
|
|
FilterInfo filterInfo = new FilterInfo();
|
|
AuthorizationContext authContext = new AuthorizationContext();
|
|
|
|
Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>();
|
|
mockHelper.CallBase = true;
|
|
mockHelper.Setup(h => h.PublicGetControllerDescriptor(context)).Returns(cd).Verifiable();
|
|
mockHelper.Setup(h => h.PublicFindAction(context, cd, "SomeMethod")).Returns(ad).Verifiable();
|
|
mockHelper.Setup(h => h.PublicGetFilters(context, ad)).Returns(filterInfo).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeAuthorizationFilters(context, filterInfo.AuthorizationFilters, ad)).Returns(authContext).Verifiable();
|
|
ControllerActionInvokerHelper helper = mockHelper.Object;
|
|
|
|
// Act
|
|
helper.InvokeAction(context, "SomeMethod");
|
|
|
|
// Assert
|
|
Assert.True(validateInputWasCalled);
|
|
mockHelper.Verify();
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionDoesNotCallValidateRequestForChildActions()
|
|
{
|
|
// Arrange
|
|
ControllerBase controller = new Mock<ControllerBase>().Object;
|
|
controller.ValidateRequest = true;
|
|
|
|
ControllerContext context = GetControllerContext(controller, null);
|
|
Mock.Get<ControllerContext>(context).SetupGet(c => c.IsChildAction).Returns(true);
|
|
ControllerDescriptor cd = new Mock<ControllerDescriptor>().Object;
|
|
ActionDescriptor ad = new Mock<ActionDescriptor>().Object;
|
|
FilterInfo filterInfo = new FilterInfo();
|
|
AuthorizationContext authContext = new AuthorizationContext();
|
|
|
|
Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>();
|
|
mockHelper.CallBase = true;
|
|
mockHelper.Setup(h => h.PublicGetControllerDescriptor(context)).Returns(cd).Verifiable();
|
|
mockHelper.Setup(h => h.PublicFindAction(context, cd, "SomeMethod")).Returns(ad).Verifiable();
|
|
mockHelper.Setup(h => h.PublicGetFilters(context, ad)).Returns(filterInfo).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeAuthorizationFilters(context, filterInfo.AuthorizationFilters, ad)).Returns(authContext).Verifiable();
|
|
ControllerActionInvokerHelper helper = mockHelper.Object;
|
|
|
|
// Act
|
|
helper.InvokeAction(context, "SomeMethod"); // No exception thrown
|
|
|
|
// Assert
|
|
mockHelper.Verify();
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionMethodFilterWhereContinuationThrowsExceptionAndIsHandled()
|
|
{
|
|
// Arrange
|
|
List<string> actions = new List<string>();
|
|
MethodInfo mi = typeof(object).GetMethod("ToString");
|
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
|
Exception exception = new Exception();
|
|
ActionDescriptor action = new Mock<ActionDescriptor>().Object;
|
|
|
|
ActionFilterImpl filter = new ActionFilterImpl()
|
|
{
|
|
OnActionExecutingImpl = delegate(ActionExecutingContext filterContext) { actions.Add("OnActionExecuting"); },
|
|
OnActionExecutedImpl = delegate(ActionExecutedContext filterContext)
|
|
{
|
|
actions.Add("OnActionExecuted");
|
|
Assert.Same(exception, filterContext.Exception);
|
|
Assert.Same(action, filterContext.ActionDescriptor);
|
|
Assert.False(filterContext.ExceptionHandled);
|
|
filterContext.ExceptionHandled = true;
|
|
}
|
|
};
|
|
Func<ActionExecutedContext> continuation = delegate
|
|
{
|
|
actions.Add("Continuation");
|
|
throw exception;
|
|
};
|
|
|
|
ActionExecutingContext context = new ActionExecutingContext(GetControllerContext(new EmptyController()), action, parameters);
|
|
|
|
// Act
|
|
ActionExecutedContext result = ControllerActionInvoker.InvokeActionMethodFilter(filter, context, continuation);
|
|
|
|
// Assert
|
|
Assert.Equal(3, actions.Count);
|
|
Assert.Equal("OnActionExecuting", actions[0]);
|
|
Assert.Equal("Continuation", actions[1]);
|
|
Assert.Equal("OnActionExecuted", actions[2]);
|
|
Assert.Same(exception, result.Exception);
|
|
Assert.Same(action, result.ActionDescriptor);
|
|
Assert.True(result.ExceptionHandled);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionMethodFilterWhereContinuationThrowsExceptionAndIsNotHandled()
|
|
{
|
|
// Arrange
|
|
List<string> actions = new List<string>();
|
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
|
ActionDescriptor action = new Mock<ActionDescriptor>().Object;
|
|
|
|
ActionFilterImpl filter = new ActionFilterImpl()
|
|
{
|
|
OnActionExecutingImpl = delegate(ActionExecutingContext filterContext) { actions.Add("OnActionExecuting"); },
|
|
OnActionExecutedImpl = delegate(ActionExecutedContext filterContext)
|
|
{
|
|
Assert.NotNull(filterContext.Exception);
|
|
Assert.Equal("Some exception message.", filterContext.Exception.Message);
|
|
Assert.Same(action, filterContext.ActionDescriptor);
|
|
actions.Add("OnActionExecuted");
|
|
}
|
|
};
|
|
Func<ActionExecutedContext> continuation = delegate
|
|
{
|
|
actions.Add("Continuation");
|
|
throw new Exception("Some exception message.");
|
|
};
|
|
|
|
ActionExecutingContext context = new ActionExecutingContext(GetControllerContext(new EmptyController()), action, parameters);
|
|
|
|
// Act & Assert
|
|
Assert.Throws<Exception>(
|
|
delegate { ControllerActionInvoker.InvokeActionMethodFilter(filter, context, continuation); },
|
|
"Some exception message.");
|
|
Assert.Equal(3, actions.Count);
|
|
Assert.Equal("OnActionExecuting", actions[0]);
|
|
Assert.Equal("Continuation", actions[1]);
|
|
Assert.Equal("OnActionExecuted", actions[2]);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionMethodFilterWhereContinuationThrowsThreadAbortException()
|
|
{
|
|
// Arrange
|
|
List<string> actions = new List<string>();
|
|
ActionResult actionResult = new EmptyResult();
|
|
ActionDescriptor action = new Mock<ActionDescriptor>().Object;
|
|
|
|
ActionFilterImpl filter = new ActionFilterImpl()
|
|
{
|
|
OnActionExecutingImpl = delegate(ActionExecutingContext filterContext) { actions.Add("OnActionExecuting"); },
|
|
OnActionExecutedImpl = delegate(ActionExecutedContext filterContext)
|
|
{
|
|
Thread.ResetAbort();
|
|
actions.Add("OnActionExecuted");
|
|
Assert.Null(filterContext.Exception);
|
|
Assert.False(filterContext.ExceptionHandled);
|
|
Assert.Same(action, filterContext.ActionDescriptor);
|
|
}
|
|
};
|
|
Func<ActionExecutedContext> continuation = delegate
|
|
{
|
|
actions.Add("Continuation");
|
|
Thread.CurrentThread.Abort();
|
|
return null;
|
|
};
|
|
|
|
ActionExecutingContext context = new ActionExecutingContext(new Mock<ControllerContext>().Object, action, new Dictionary<string, object>());
|
|
|
|
// Act & Assert
|
|
Assert.Throws<ThreadAbortException>(
|
|
delegate { ControllerActionInvoker.InvokeActionMethodFilter(filter, context, continuation); },
|
|
"Thread was being aborted.");
|
|
Assert.Equal(3, actions.Count);
|
|
Assert.Equal("OnActionExecuting", actions[0]);
|
|
Assert.Equal("Continuation", actions[1]);
|
|
Assert.Equal("OnActionExecuted", actions[2]);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionMethodFilterWhereOnActionExecutingCancels()
|
|
{
|
|
// Arrange
|
|
bool wasCalled = false;
|
|
ActionDescriptor ad = new Mock<ActionDescriptor>().Object;
|
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
|
|
|
ActionResult actionResult = new EmptyResult();
|
|
ActionDescriptor action = new Mock<ActionDescriptor>().Object;
|
|
|
|
ActionFilterImpl filter = new ActionFilterImpl()
|
|
{
|
|
OnActionExecutingImpl = delegate(ActionExecutingContext filterContext)
|
|
{
|
|
Assert.False(wasCalled);
|
|
wasCalled = true;
|
|
filterContext.Result = actionResult;
|
|
},
|
|
};
|
|
Func<ActionExecutedContext> continuation = delegate
|
|
{
|
|
Assert.True(false, "The continuation should not be called.");
|
|
return null;
|
|
};
|
|
|
|
ActionExecutingContext context = new ActionExecutingContext(GetControllerContext(new EmptyController()), action, parameters);
|
|
|
|
// Act
|
|
ActionExecutedContext result = ControllerActionInvoker.InvokeActionMethodFilter(filter, context, continuation);
|
|
|
|
// Assert
|
|
Assert.True(wasCalled);
|
|
Assert.Null(result.Exception);
|
|
Assert.True(result.Canceled);
|
|
Assert.Same(actionResult, result.Result);
|
|
Assert.Same(action, result.ActionDescriptor);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionMethodFilterWithNormalControlFlow()
|
|
{
|
|
// Arrange
|
|
List<string> actions = new List<string>();
|
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
|
ActionDescriptor action = new Mock<ActionDescriptor>().Object;
|
|
|
|
ActionExecutingContext preContext = new ActionExecutingContext(GetControllerContext(new EmptyController()), action, parameters);
|
|
Mock<ActionExecutedContext> mockPostContext = new Mock<ActionExecutedContext>();
|
|
|
|
ActionFilterImpl filter = new ActionFilterImpl()
|
|
{
|
|
OnActionExecutingImpl = delegate(ActionExecutingContext filterContext)
|
|
{
|
|
Assert.Same(parameters, filterContext.ActionParameters);
|
|
Assert.Null(filterContext.Result);
|
|
actions.Add("OnActionExecuting");
|
|
},
|
|
OnActionExecutedImpl = delegate(ActionExecutedContext filterContext)
|
|
{
|
|
Assert.Equal(mockPostContext.Object, filterContext);
|
|
actions.Add("OnActionExecuted");
|
|
}
|
|
};
|
|
Func<ActionExecutedContext> continuation = delegate
|
|
{
|
|
actions.Add("Continuation");
|
|
return mockPostContext.Object;
|
|
};
|
|
|
|
// Act
|
|
ActionExecutedContext result = ControllerActionInvoker.InvokeActionMethodFilter(filter, preContext, continuation);
|
|
|
|
// Assert
|
|
Assert.Equal(3, actions.Count);
|
|
Assert.Equal("OnActionExecuting", actions[0]);
|
|
Assert.Equal("Continuation", actions[1]);
|
|
Assert.Equal("OnActionExecuted", actions[2]);
|
|
Assert.Same(result, mockPostContext.Object);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionInvokesExceptionFiltersAndExecutesResultIfExceptionHandled()
|
|
{
|
|
// Arrange
|
|
ControllerBase controller = new Mock<ControllerBase>().Object;
|
|
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new Mock<ControllerDescriptor>().Object;
|
|
ActionDescriptor ad = new Mock<ActionDescriptor>().Object;
|
|
FilterInfo filterInfo = new FilterInfo();
|
|
|
|
Exception exception = new Exception();
|
|
ActionResult actionResult = new EmptyResult();
|
|
ExceptionContext exContext = new ExceptionContext(context, exception)
|
|
{
|
|
ExceptionHandled = true,
|
|
Result = actionResult
|
|
};
|
|
|
|
Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>() { CallBase = true };
|
|
mockHelper.Setup(h => h.PublicGetControllerDescriptor(context)).Returns(cd).Verifiable();
|
|
mockHelper.Setup(h => h.PublicFindAction(context, cd, "SomeMethod")).Returns(ad).Verifiable();
|
|
mockHelper.Setup(h => h.PublicGetFilters(context, ad)).Returns(filterInfo).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeAuthorizationFilters(context, filterInfo.AuthorizationFilters, ad)).Throws(exception).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeExceptionFilters(context, filterInfo.ExceptionFilters, exception)).Returns(exContext).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeActionResult(context, actionResult)).Verifiable();
|
|
ControllerActionInvokerHelper helper = mockHelper.Object;
|
|
|
|
// Act
|
|
bool retVal = helper.InvokeAction(context, "SomeMethod");
|
|
Assert.True(retVal);
|
|
mockHelper.Verify();
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionInvokesExceptionFiltersAndRethrowsExceptionIfNotHandled()
|
|
{
|
|
// Arrange
|
|
ControllerBase controller = new Mock<ControllerBase>().Object;
|
|
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new Mock<ControllerDescriptor>().Object;
|
|
ActionDescriptor ad = new Mock<ActionDescriptor>().Object;
|
|
FilterInfo filterInfo = new FilterInfo();
|
|
|
|
Exception exception = new Exception();
|
|
ExceptionContext exContext = new ExceptionContext(context, exception);
|
|
|
|
Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>() { CallBase = true };
|
|
mockHelper.Setup(h => h.PublicGetControllerDescriptor(context)).Returns(cd).Verifiable();
|
|
mockHelper.Setup(h => h.PublicFindAction(context, cd, "SomeMethod")).Returns(ad).Verifiable();
|
|
mockHelper.Setup(h => h.PublicGetFilters(context, ad)).Returns(filterInfo).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeAuthorizationFilters(context, filterInfo.AuthorizationFilters, ad)).Throws(exception).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeExceptionFilters(context, filterInfo.ExceptionFilters, exception)).Returns(exContext).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeActionResult(context, It.IsAny<ActionResult>())).Callback(delegate { Assert.True(false, "InvokeActionResult() shouldn't be called if the exception was unhandled by filters."); });
|
|
ControllerActionInvokerHelper helper = mockHelper.Object;
|
|
|
|
// Act
|
|
Exception thrownException = Assert.Throws<Exception>(
|
|
delegate { helper.InvokeAction(context, "SomeMethod"); });
|
|
|
|
// Assert
|
|
Assert.Same(exception, thrownException);
|
|
mockHelper.Verify();
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionInvokesResultIfAuthorizationFilterReturnsResult()
|
|
{
|
|
// Arrange
|
|
ControllerBase controller = new Mock<ControllerBase>().Object;
|
|
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new Mock<ControllerDescriptor>().Object;
|
|
ActionDescriptor ad = new Mock<ActionDescriptor>().Object;
|
|
FilterInfo filterInfo = new FilterInfo();
|
|
|
|
ActionResult actionResult = new EmptyResult();
|
|
ActionExecutedContext postContext = new ActionExecutedContext(context, ad, false /* canceled */, null /* exception */)
|
|
{
|
|
Result = actionResult
|
|
};
|
|
AuthorizationContext authContext = new AuthorizationContext() { Result = actionResult };
|
|
|
|
Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>() { CallBase = true };
|
|
mockHelper.Setup(h => h.PublicGetControllerDescriptor(context)).Returns(cd).Verifiable();
|
|
mockHelper.Setup(h => h.PublicFindAction(context, cd, "SomeMethod")).Returns(ad).Verifiable();
|
|
mockHelper.Setup(h => h.PublicGetFilters(context, ad)).Returns(filterInfo).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeAuthorizationFilters(context, filterInfo.AuthorizationFilters, ad)).Returns(authContext).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeActionResult(context, actionResult)).Verifiable();
|
|
ControllerActionInvokerHelper helper = mockHelper.Object;
|
|
|
|
// Act
|
|
bool retVal = helper.InvokeAction(context, "SomeMethod");
|
|
Assert.True(retVal);
|
|
mockHelper.Verify();
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionMethod()
|
|
{
|
|
// Arrange
|
|
EmptyController controller = new EmptyController();
|
|
ControllerContext controllerContext = GetControllerContext(controller);
|
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
|
|
|
ActionResult expectedResult = new Mock<ActionResult>().Object;
|
|
|
|
Mock<ActionDescriptor> mockAd = new Mock<ActionDescriptor>();
|
|
mockAd.Setup(ad => ad.Execute(controllerContext, parameters)).Returns("hello world");
|
|
|
|
Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>() { CallBase = true };
|
|
mockHelper.Setup(h => h.PublicCreateActionResult(controllerContext, mockAd.Object, "hello world")).Returns(expectedResult);
|
|
ControllerActionInvokerHelper helper = mockHelper.Object;
|
|
|
|
// Act
|
|
ActionResult returnedResult = helper.PublicInvokeActionMethod(controllerContext, mockAd.Object, parameters);
|
|
|
|
// Assert
|
|
Assert.Same(expectedResult, returnedResult);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionMethodWithFiltersOrdersFiltersCorrectly()
|
|
{
|
|
// Arrange
|
|
List<string> actions = new List<string>();
|
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
|
ActionResult actionResult = new EmptyResult();
|
|
|
|
ActionFilterImpl filter1 = new ActionFilterImpl()
|
|
{
|
|
OnActionExecutingImpl = delegate(ActionExecutingContext filterContext) { actions.Add("OnActionExecuting1"); },
|
|
OnActionExecutedImpl = delegate(ActionExecutedContext filterContext) { actions.Add("OnActionExecuted1"); }
|
|
};
|
|
ActionFilterImpl filter2 = new ActionFilterImpl()
|
|
{
|
|
OnActionExecutingImpl = delegate(ActionExecutingContext filterContext) { actions.Add("OnActionExecuting2"); },
|
|
OnActionExecutedImpl = delegate(ActionExecutedContext filterContext) { actions.Add("OnActionExecuted2"); }
|
|
};
|
|
Func<ActionResult> continuation = delegate
|
|
{
|
|
actions.Add("Continuation");
|
|
return new EmptyResult();
|
|
};
|
|
ControllerBase controller = new ContinuationController(continuation);
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ActionDescriptor actionDescriptor = new ReflectedActionDescriptor(ContinuationController.GoMethod, "someName", new Mock<ControllerDescriptor>().Object);
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
List<IActionFilter> filters = new List<IActionFilter>() { filter1, filter2 };
|
|
|
|
// Act
|
|
helper.PublicInvokeActionMethodWithFilters(context, filters, actionDescriptor, parameters);
|
|
|
|
// Assert
|
|
Assert.Equal(5, actions.Count);
|
|
Assert.Equal("OnActionExecuting1", actions[0]);
|
|
Assert.Equal("OnActionExecuting2", actions[1]);
|
|
Assert.Equal("Continuation", actions[2]);
|
|
Assert.Equal("OnActionExecuted2", actions[3]);
|
|
Assert.Equal("OnActionExecuted1", actions[4]);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionMethodWithFiltersPassesArgumentsCorrectly()
|
|
{
|
|
// Arrange
|
|
bool wasCalled = false;
|
|
MethodInfo mi = ContinuationController.GoMethod;
|
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
|
ActionResult actionResult = new EmptyResult();
|
|
ActionFilterImpl filter = new ActionFilterImpl()
|
|
{
|
|
OnActionExecutingImpl = delegate(ActionExecutingContext filterContext)
|
|
{
|
|
Assert.Same(parameters, filterContext.ActionParameters);
|
|
Assert.False(wasCalled);
|
|
wasCalled = true;
|
|
filterContext.Result = actionResult;
|
|
}
|
|
};
|
|
Func<ActionResult> continuation = delegate
|
|
{
|
|
Assert.True(false, "Continuation should not be called.");
|
|
return null;
|
|
};
|
|
ControllerBase controller = new ContinuationController(continuation);
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
ActionDescriptor actionDescriptor = new ReflectedActionDescriptor(ContinuationController.GoMethod, "someName", new Mock<ControllerDescriptor>().Object);
|
|
List<IActionFilter> filters = new List<IActionFilter>() { filter };
|
|
|
|
// Act
|
|
ActionExecutedContext result = helper.PublicInvokeActionMethodWithFilters(context, filters, actionDescriptor, parameters);
|
|
|
|
// Assert
|
|
Assert.True(wasCalled);
|
|
Assert.Null(result.Exception);
|
|
Assert.False(result.ExceptionHandled);
|
|
Assert.Same(actionResult, result.Result);
|
|
Assert.Same(actionDescriptor, result.ActionDescriptor);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionPropagatesThreadAbortException()
|
|
{
|
|
// Arrange
|
|
ControllerBase controller = new Mock<ControllerBase>().Object;
|
|
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new Mock<ControllerDescriptor>().Object;
|
|
ActionDescriptor ad = new Mock<ActionDescriptor>().Object;
|
|
FilterInfo filterInfo = new FilterInfo();
|
|
|
|
ActionResult actionResult = new EmptyResult();
|
|
ActionExecutedContext postContext = new ActionExecutedContext(context, ad, false /* canceled */, null /* exception */)
|
|
{
|
|
Result = actionResult
|
|
};
|
|
AuthorizationContext authContext = new AuthorizationContext() { Result = actionResult };
|
|
|
|
Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>() { CallBase = true };
|
|
mockHelper.Setup(h => h.PublicGetControllerDescriptor(context)).Returns(cd).Verifiable();
|
|
mockHelper.Setup(h => h.PublicFindAction(context, cd, "SomeMethod")).Returns(ad).Verifiable();
|
|
mockHelper.Setup(h => h.PublicGetFilters(context, ad)).Returns(filterInfo).Verifiable();
|
|
mockHelper
|
|
.Setup(h => h.PublicInvokeAuthorizationFilters(context, filterInfo.AuthorizationFilters, ad))
|
|
.Returns(
|
|
delegate(ControllerContext cc, IList<IAuthorizationFilter> f, ActionDescriptor a)
|
|
{
|
|
Thread.CurrentThread.Abort();
|
|
return null;
|
|
});
|
|
ControllerActionInvokerHelper helper = mockHelper.Object;
|
|
|
|
bool wasAborted = false;
|
|
|
|
// Act
|
|
try
|
|
{
|
|
helper.InvokeAction(context, "SomeMethod");
|
|
}
|
|
catch (ThreadAbortException)
|
|
{
|
|
wasAborted = true;
|
|
Thread.ResetAbort();
|
|
}
|
|
|
|
// Assert
|
|
Assert.True(wasAborted);
|
|
mockHelper.Verify();
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionResultWithFiltersPassesSameContextObjectToInnerFilters()
|
|
{
|
|
// Arrange
|
|
ControllerBase controller = new Mock<ControllerBase>().Object;
|
|
ControllerContext context = GetControllerContext(controller);
|
|
|
|
ResultExecutingContext storedContext = null;
|
|
ActionResult result = new EmptyResult();
|
|
List<IResultFilter> filters = new List<IResultFilter>()
|
|
{
|
|
new ActionFilterImpl()
|
|
{
|
|
OnResultExecutingImpl = delegate(ResultExecutingContext ctx) { storedContext = ctx; },
|
|
OnResultExecutedImpl = delegate { }
|
|
},
|
|
new ActionFilterImpl()
|
|
{
|
|
OnResultExecutingImpl = delegate(ResultExecutingContext ctx) { Assert.Same(storedContext, ctx); },
|
|
OnResultExecutedImpl = delegate { }
|
|
},
|
|
};
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
// Act
|
|
ResultExecutedContext postContext = helper.PublicInvokeActionResultWithFilters(context, filters, result);
|
|
|
|
// Assert
|
|
Assert.Same(result, postContext.Result);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionReturnsFalseIfMethodNotFound()
|
|
{
|
|
// Arrange
|
|
var controller = new BlankController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerActionInvoker invoker = new ControllerActionInvoker();
|
|
|
|
// Act
|
|
bool retVal = invoker.InvokeAction(context, "foo");
|
|
|
|
// Assert
|
|
Assert.False(retVal);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionThrowsIfControllerContextIsNull()
|
|
{
|
|
// Arrange
|
|
ControllerActionInvoker invoker = new ControllerActionInvoker();
|
|
|
|
// Act & Assert
|
|
Assert.ThrowsArgumentNull(
|
|
delegate { invoker.InvokeAction(null, "actionName"); }, "controllerContext");
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionWithEmptyActionNameThrows()
|
|
{
|
|
// Arrange
|
|
var controller = new BasicMethodInvokeController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerActionInvoker invoker = new ControllerActionInvoker();
|
|
|
|
// Act & Assert
|
|
Assert.ThrowsArgumentNullOrEmpty(
|
|
delegate { invoker.InvokeAction(context, String.Empty); },
|
|
"actionName");
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionWithNullActionNameThrows()
|
|
{
|
|
// Arrange
|
|
var controller = new BasicMethodInvokeController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerActionInvoker invoker = new ControllerActionInvoker();
|
|
|
|
// Act & Assert
|
|
Assert.ThrowsArgumentNullOrEmpty(
|
|
delegate { invoker.InvokeAction(context, null /* actionName */); },
|
|
"actionName");
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeActionWithResultExceptionInvokesExceptionFiltersAndExecutesResultIfExceptionHandled()
|
|
{
|
|
// Arrange
|
|
ControllerBase controller = new Mock<ControllerBase>().Object;
|
|
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerDescriptor cd = new Mock<ControllerDescriptor>().Object;
|
|
ActionDescriptor ad = new Mock<ActionDescriptor>().Object;
|
|
IDictionary<string, object> parameters = new Dictionary<string, object>();
|
|
FilterInfo filterInfo = new FilterInfo();
|
|
AuthorizationContext authContext = new AuthorizationContext();
|
|
|
|
Exception exception = new Exception();
|
|
ActionResult actionResult = new EmptyResult();
|
|
ActionExecutedContext postContext = new ActionExecutedContext(context, ad, false /* canceled */, null /* exception */)
|
|
{
|
|
Result = actionResult
|
|
};
|
|
ExceptionContext exContext = new ExceptionContext(context, exception)
|
|
{
|
|
ExceptionHandled = true,
|
|
Result = actionResult
|
|
};
|
|
|
|
Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>() { CallBase = true };
|
|
mockHelper.Setup(h => h.PublicGetControllerDescriptor(context)).Returns(cd).Verifiable();
|
|
mockHelper.Setup(h => h.PublicFindAction(context, cd, "SomeMethod")).Returns(ad).Verifiable();
|
|
mockHelper.Setup(h => h.PublicGetFilters(context, ad)).Returns(filterInfo).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeAuthorizationFilters(context, filterInfo.AuthorizationFilters, ad)).Returns(authContext).Verifiable();
|
|
mockHelper.Setup(h => h.PublicGetParameterValues(context, ad)).Returns(parameters).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeActionMethodWithFilters(context, filterInfo.ActionFilters, ad, parameters)).Returns(postContext).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeActionResultWithFilters(context, filterInfo.ResultFilters, actionResult)).Throws(exception).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeExceptionFilters(context, filterInfo.ExceptionFilters, exception)).Returns(exContext).Verifiable();
|
|
mockHelper.Setup(h => h.PublicInvokeActionResult(context, actionResult)).Verifiable();
|
|
ControllerActionInvokerHelper helper = mockHelper.Object;
|
|
|
|
// Act
|
|
bool retVal = helper.InvokeAction(context, "SomeMethod");
|
|
Assert.True(retVal, "InvokeAction() should return True on success.");
|
|
mockHelper.Verify();
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeAuthorizationFilters()
|
|
{
|
|
// Arrange
|
|
ControllerBase controller = new Mock<ControllerBase>().Object;
|
|
ActionDescriptor ad = new Mock<ActionDescriptor>().Object;
|
|
ControllerContext controllerContext = GetControllerContext(controller);
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
List<AuthorizationFilterHelper> callQueue = new List<AuthorizationFilterHelper>();
|
|
AuthorizationFilterHelper filter1 = new AuthorizationFilterHelper(callQueue);
|
|
AuthorizationFilterHelper filter2 = new AuthorizationFilterHelper(callQueue);
|
|
IAuthorizationFilter[] filters = new IAuthorizationFilter[] { filter1, filter2 };
|
|
|
|
// Act
|
|
AuthorizationContext postContext = helper.PublicInvokeAuthorizationFilters(controllerContext, filters, ad);
|
|
|
|
// Assert
|
|
Assert.Equal(ad, postContext.ActionDescriptor);
|
|
Assert.Equal(2, callQueue.Count);
|
|
Assert.Same(filter1, callQueue[0]);
|
|
Assert.Same(filter2, callQueue[1]);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeAuthorizationFiltersStopsExecutingIfResultProvided()
|
|
{
|
|
// Arrange
|
|
ControllerBase controller = new Mock<ControllerBase>().Object;
|
|
ActionDescriptor ad = new Mock<ActionDescriptor>().Object;
|
|
ControllerContext controllerContext = GetControllerContext(controller);
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
ActionResult result = new EmptyResult();
|
|
|
|
List<AuthorizationFilterHelper> callQueue = new List<AuthorizationFilterHelper>();
|
|
AuthorizationFilterHelper filter1 = new AuthorizationFilterHelper(callQueue) { ShortCircuitResult = result };
|
|
AuthorizationFilterHelper filter2 = new AuthorizationFilterHelper(callQueue);
|
|
IAuthorizationFilter[] filters = new IAuthorizationFilter[] { filter1, filter2 };
|
|
|
|
// Act
|
|
AuthorizationContext postContext = helper.PublicInvokeAuthorizationFilters(controllerContext, filters, ad);
|
|
|
|
// Assert
|
|
Assert.Equal(ad, postContext.ActionDescriptor);
|
|
Assert.Same(result, postContext.Result);
|
|
Assert.Single(callQueue);
|
|
Assert.Same(filter1, callQueue[0]);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeExceptionFilters()
|
|
{
|
|
// Arrange
|
|
ControllerBase controller = new Mock<ControllerBase>().Object;
|
|
Exception exception = new Exception();
|
|
ControllerContext controllerContext = GetControllerContext(controller);
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
List<ExceptionFilterHelper> callQueue = new List<ExceptionFilterHelper>();
|
|
ExceptionFilterHelper filter1 = new ExceptionFilterHelper(callQueue);
|
|
ExceptionFilterHelper filter2 = new ExceptionFilterHelper(callQueue);
|
|
IExceptionFilter[] filters = new IExceptionFilter[] { filter1, filter2 };
|
|
|
|
// Act
|
|
ExceptionContext postContext = helper.PublicInvokeExceptionFilters(controllerContext, filters, exception);
|
|
|
|
// Assert
|
|
Assert.Same(exception, postContext.Exception);
|
|
Assert.False(postContext.ExceptionHandled);
|
|
Assert.Same(filter1.ContextPassed, filter2.ContextPassed);
|
|
Assert.Equal(2, callQueue.Count);
|
|
Assert.Same(filter2, callQueue[0]); // Exception filters are executed in reverse order
|
|
Assert.Same(filter1, callQueue[1]);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeExceptionFiltersContinuesExecutingIfExceptionHandled()
|
|
{
|
|
// Arrange
|
|
ControllerBase controller = new Mock<ControllerBase>().Object;
|
|
Exception exception = new Exception();
|
|
ControllerContext controllerContext = GetControllerContext(controller);
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
|
|
List<ExceptionFilterHelper> callQueue = new List<ExceptionFilterHelper>();
|
|
ExceptionFilterHelper filter1 = new ExceptionFilterHelper(callQueue) { ShouldHandleException = true };
|
|
ExceptionFilterHelper filter2 = new ExceptionFilterHelper(callQueue);
|
|
IExceptionFilter[] filters = new IExceptionFilter[] { filter1, filter2 };
|
|
|
|
// Act
|
|
ExceptionContext postContext = helper.PublicInvokeExceptionFilters(controllerContext, filters, exception);
|
|
|
|
// Assert
|
|
Assert.Same(exception, postContext.Exception);
|
|
Assert.True(postContext.ExceptionHandled);
|
|
Assert.Same(filter1.ContextPassed, filter2.ContextPassed);
|
|
Assert.Equal(2, callQueue.Count);
|
|
Assert.Same(filter2, callQueue[0]); // Exception filters are executed in reverse order
|
|
Assert.Same(filter1, callQueue[1]);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeResultFiltersOrdersFiltersCorrectly()
|
|
{
|
|
// Arrange
|
|
List<string> actions = new List<string>();
|
|
ActionFilterImpl filter1 = new ActionFilterImpl()
|
|
{
|
|
OnResultExecutingImpl = delegate(ResultExecutingContext filterContext) { actions.Add("OnResultExecuting1"); },
|
|
OnResultExecutedImpl = delegate(ResultExecutedContext filterContext) { actions.Add("OnResultExecuted1"); }
|
|
};
|
|
ActionFilterImpl filter2 = new ActionFilterImpl()
|
|
{
|
|
OnResultExecutingImpl = delegate(ResultExecutingContext filterContext) { actions.Add("OnResultExecuting2"); },
|
|
OnResultExecutedImpl = delegate(ResultExecutedContext filterContext) { actions.Add("OnResultExecuted2"); }
|
|
};
|
|
Action continuation = delegate { actions.Add("Continuation"); };
|
|
ActionResult actionResult = new ContinuationResult(continuation);
|
|
ControllerBase controller = new Mock<ControllerBase>().Object;
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
List<IResultFilter> filters = new List<IResultFilter>() { filter1, filter2 };
|
|
|
|
// Act
|
|
helper.PublicInvokeActionResultWithFilters(context, filters, actionResult);
|
|
|
|
// Assert
|
|
Assert.Equal(5, actions.Count);
|
|
Assert.Equal("OnResultExecuting1", actions[0]);
|
|
Assert.Equal("OnResultExecuting2", actions[1]);
|
|
Assert.Equal("Continuation", actions[2]);
|
|
Assert.Equal("OnResultExecuted2", actions[3]);
|
|
Assert.Equal("OnResultExecuted1", actions[4]);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeResultFiltersPassesArgumentsCorrectly()
|
|
{
|
|
// Arrange
|
|
bool wasCalled = false;
|
|
Action continuation = delegate { Assert.True(false, "Continuation should not be called."); };
|
|
ActionResult actionResult = new ContinuationResult(continuation);
|
|
ControllerBase controller = new Mock<ControllerBase>().Object;
|
|
ControllerContext context = GetControllerContext(controller);
|
|
ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper();
|
|
ActionFilterImpl filter = new ActionFilterImpl()
|
|
{
|
|
OnResultExecutingImpl = delegate(ResultExecutingContext filterContext)
|
|
{
|
|
Assert.Same(actionResult, filterContext.Result);
|
|
Assert.False(wasCalled);
|
|
wasCalled = true;
|
|
filterContext.Cancel = true;
|
|
}
|
|
};
|
|
|
|
List<IResultFilter> filters = new List<IResultFilter>() { filter };
|
|
|
|
// Act
|
|
ResultExecutedContext result = helper.PublicInvokeActionResultWithFilters(context, filters, actionResult);
|
|
|
|
// Assert
|
|
Assert.True(wasCalled);
|
|
Assert.Null(result.Exception);
|
|
Assert.False(result.ExceptionHandled);
|
|
Assert.Same(actionResult, result.Result);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeResultFilterWhereContinuationThrowsExceptionAndIsHandled()
|
|
{
|
|
// Arrange
|
|
List<string> actions = new List<string>();
|
|
ActionResult actionResult = new EmptyResult();
|
|
Exception exception = new Exception();
|
|
ActionFilterImpl filter = new ActionFilterImpl()
|
|
{
|
|
OnResultExecutingImpl = delegate(ResultExecutingContext filterContext) { actions.Add("OnResultExecuting"); },
|
|
OnResultExecutedImpl = delegate(ResultExecutedContext filterContext)
|
|
{
|
|
actions.Add("OnResultExecuted");
|
|
Assert.Same(actionResult, filterContext.Result);
|
|
Assert.Same(exception, filterContext.Exception);
|
|
Assert.False(filterContext.ExceptionHandled);
|
|
filterContext.ExceptionHandled = true;
|
|
}
|
|
};
|
|
Func<ResultExecutedContext> continuation = delegate
|
|
{
|
|
actions.Add("Continuation");
|
|
throw exception;
|
|
};
|
|
|
|
Mock<ResultExecutingContext> mockResultExecutingContext = new Mock<ResultExecutingContext>() { DefaultValue = DefaultValue.Mock };
|
|
mockResultExecutingContext.Setup(c => c.Result).Returns(actionResult);
|
|
|
|
// Act
|
|
ResultExecutedContext result = ControllerActionInvoker.InvokeActionResultFilter(filter, mockResultExecutingContext.Object, continuation);
|
|
|
|
// Assert
|
|
Assert.Equal(3, actions.Count);
|
|
Assert.Equal("OnResultExecuting", actions[0]);
|
|
Assert.Equal("Continuation", actions[1]);
|
|
Assert.Equal("OnResultExecuted", actions[2]);
|
|
Assert.Same(exception, result.Exception);
|
|
Assert.True(result.ExceptionHandled);
|
|
Assert.Same(actionResult, result.Result);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeResultFilterWhereContinuationThrowsExceptionAndIsNotHandled()
|
|
{
|
|
// Arrange
|
|
List<string> actions = new List<string>();
|
|
ActionFilterImpl filter = new ActionFilterImpl()
|
|
{
|
|
OnResultExecutingImpl = delegate(ResultExecutingContext filterContext) { actions.Add("OnResultExecuting"); },
|
|
OnResultExecutedImpl = delegate(ResultExecutedContext filterContext) { actions.Add("OnResultExecuted"); }
|
|
};
|
|
Func<ResultExecutedContext> continuation = delegate
|
|
{
|
|
actions.Add("Continuation");
|
|
throw new Exception("Some exception message.");
|
|
};
|
|
|
|
// Act & Assert
|
|
Assert.Throws<Exception>(
|
|
delegate { ControllerActionInvoker.InvokeActionResultFilter(filter, new Mock<ResultExecutingContext>() { DefaultValue = DefaultValue.Mock }.Object, continuation); },
|
|
"Some exception message.");
|
|
Assert.Equal(3, actions.Count);
|
|
Assert.Equal("OnResultExecuting", actions[0]);
|
|
Assert.Equal("Continuation", actions[1]);
|
|
Assert.Equal("OnResultExecuted", actions[2]);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeResultFilterWhereContinuationThrowsThreadAbortException()
|
|
{
|
|
// Arrange
|
|
List<string> actions = new List<string>();
|
|
ActionResult actionResult = new EmptyResult();
|
|
|
|
Mock<ResultExecutingContext> mockPreContext = new Mock<ResultExecutingContext>() { DefaultValue = DefaultValue.Mock };
|
|
mockPreContext.Setup(c => c.Result).Returns(actionResult);
|
|
|
|
ActionFilterImpl filter = new ActionFilterImpl()
|
|
{
|
|
OnResultExecutingImpl = delegate(ResultExecutingContext filterContext) { actions.Add("OnResultExecuting"); },
|
|
OnResultExecutedImpl = delegate(ResultExecutedContext filterContext)
|
|
{
|
|
Thread.ResetAbort();
|
|
actions.Add("OnResultExecuted");
|
|
Assert.Same(actionResult, filterContext.Result);
|
|
Assert.Null(filterContext.Exception);
|
|
Assert.False(filterContext.ExceptionHandled);
|
|
}
|
|
};
|
|
Func<ResultExecutedContext> continuation = delegate
|
|
{
|
|
actions.Add("Continuation");
|
|
Thread.CurrentThread.Abort();
|
|
return null;
|
|
};
|
|
|
|
// Act & Assert
|
|
Assert.Throws<ThreadAbortException>(
|
|
delegate { ControllerActionInvoker.InvokeActionResultFilter(filter, mockPreContext.Object, continuation); },
|
|
"Thread was being aborted.");
|
|
Assert.Equal(3, actions.Count);
|
|
Assert.Equal("OnResultExecuting", actions[0]);
|
|
Assert.Equal("Continuation", actions[1]);
|
|
Assert.Equal("OnResultExecuted", actions[2]);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeResultFilterWhereOnResultExecutingCancels()
|
|
{
|
|
// Arrange
|
|
bool wasCalled = false;
|
|
MethodInfo mi = typeof(object).GetMethod("ToString");
|
|
object[] paramValues = new object[0];
|
|
ActionResult actionResult = new EmptyResult();
|
|
ActionFilterImpl filter = new ActionFilterImpl()
|
|
{
|
|
OnResultExecutingImpl = delegate(ResultExecutingContext filterContext)
|
|
{
|
|
Assert.False(wasCalled);
|
|
wasCalled = true;
|
|
filterContext.Cancel = true;
|
|
},
|
|
};
|
|
Func<ResultExecutedContext> continuation = delegate
|
|
{
|
|
Assert.True(false, "The continuation should not be called.");
|
|
return null;
|
|
};
|
|
|
|
Mock<ResultExecutingContext> mockResultExecutingContext = new Mock<ResultExecutingContext>() { DefaultValue = DefaultValue.Mock };
|
|
mockResultExecutingContext.Setup(c => c.Result).Returns(actionResult);
|
|
|
|
// Act
|
|
ResultExecutedContext result = ControllerActionInvoker.InvokeActionResultFilter(filter, mockResultExecutingContext.Object, continuation);
|
|
|
|
// Assert
|
|
Assert.True(wasCalled);
|
|
Assert.Null(result.Exception);
|
|
Assert.True(result.Canceled);
|
|
Assert.Same(actionResult, result.Result);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeResultFilterWithNormalControlFlow()
|
|
{
|
|
// Arrange
|
|
List<string> actions = new List<string>();
|
|
ActionResult actionResult = new EmptyResult();
|
|
|
|
Mock<ResultExecutedContext> mockPostContext = new Mock<ResultExecutedContext>();
|
|
mockPostContext.Setup(c => c.Result).Returns(actionResult);
|
|
|
|
ActionFilterImpl filter = new ActionFilterImpl()
|
|
{
|
|
OnResultExecutingImpl = delegate(ResultExecutingContext filterContext)
|
|
{
|
|
Assert.Same(actionResult, filterContext.Result);
|
|
Assert.False(filterContext.Cancel);
|
|
actions.Add("OnResultExecuting");
|
|
},
|
|
OnResultExecutedImpl = delegate(ResultExecutedContext filterContext)
|
|
{
|
|
Assert.Equal(mockPostContext.Object, filterContext);
|
|
actions.Add("OnResultExecuted");
|
|
}
|
|
};
|
|
Func<ResultExecutedContext> continuation = delegate
|
|
{
|
|
actions.Add("Continuation");
|
|
return mockPostContext.Object;
|
|
};
|
|
|
|
Mock<ResultExecutingContext> mockResultExecutingContext = new Mock<ResultExecutingContext>();
|
|
mockResultExecutingContext.Setup(c => c.Result).Returns(actionResult);
|
|
|
|
// Act
|
|
ResultExecutedContext result = ControllerActionInvoker.InvokeActionResultFilter(filter, mockResultExecutingContext.Object, continuation);
|
|
|
|
// Assert
|
|
Assert.Equal(3, actions.Count);
|
|
Assert.Equal("OnResultExecuting", actions[0]);
|
|
Assert.Equal("Continuation", actions[1]);
|
|
Assert.Equal("OnResultExecuted", actions[2]);
|
|
Assert.Same(result, mockPostContext.Object);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvokeMethodCallsOverriddenCreateActionResult()
|
|
{
|
|
// Arrange
|
|
CustomResultInvokerController controller = new CustomResultInvokerController();
|
|
ControllerContext context = GetControllerContext(controller);
|
|
CustomResultInvoker helper = new CustomResultInvoker();
|
|
MethodInfo mi = typeof(CustomResultInvokerController).GetMethod("ReturnCustomResult");
|
|
ReflectedActionDescriptor ad = new ReflectedActionDescriptor(mi, "ReturnCustomResult", new Mock<ControllerDescriptor>().Object);
|
|
IDictionary<string, object> parameters = new Dictionary<string, object>();
|
|
|
|
// Act
|
|
ActionResult actionResult = helper.PublicInvokeActionMethod(context, ad, parameters);
|
|
|
|
// Assert (arg got passed to method + back correctly)
|
|
CustomResult customResult = Assert.IsType<CustomResult>(actionResult);
|
|
Assert.Equal("abc123", customResult.ReturnValue);
|
|
}
|
|
|
|
private static ControllerContext GetControllerContext(ControllerBase controller)
|
|
{
|
|
return GetControllerContext(controller, null);
|
|
}
|
|
|
|
private static ControllerContext GetControllerContext(ControllerBase controller, IDictionary<string, object> values, Action validateInputCallback = null)
|
|
{
|
|
SimpleValueProvider valueProvider = new SimpleValueProvider();
|
|
controller.ValueProvider = valueProvider;
|
|
if (values != null)
|
|
{
|
|
foreach (var entry in values)
|
|
{
|
|
valueProvider[entry.Key] = entry.Value;
|
|
}
|
|
}
|
|
|
|
Mock<ControllerContext> mockControllerContext = new Mock<ControllerContext>() { DefaultValue = DefaultValue.Mock };
|
|
|
|
mockControllerContext.Setup(c => c.HttpContext.Request.ValidateInput()).Callback(() =>
|
|
{
|
|
if (!controller.ValidateRequest)
|
|
{
|
|
Assert.True(false, "ValidateRequest() should not be called if the controller opted out.");
|
|
}
|
|
if (validateInputCallback != null)
|
|
{
|
|
// signal to caller that ValidateInput was called
|
|
validateInputCallback();
|
|
}
|
|
});
|
|
|
|
mockControllerContext.Setup(c => c.HttpContext.Session).Returns((HttpSessionStateBase)null);
|
|
mockControllerContext.Setup(c => c.Controller).Returns(controller);
|
|
return mockControllerContext.Object;
|
|
}
|
|
|
|
private class EmptyActionFilterAttribute : ActionFilterAttribute
|
|
{
|
|
}
|
|
|
|
private abstract class KeyedFilterAttribute : FilterAttribute
|
|
{
|
|
public string Key { get; set; }
|
|
}
|
|
|
|
private class KeyedAuthorizationFilterAttribute : KeyedFilterAttribute, IAuthorizationFilter
|
|
{
|
|
public void OnAuthorization(AuthorizationContext filterContext)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
|
|
private class KeyedActionFilterAttribute : KeyedFilterAttribute, IActionFilter, IResultFilter
|
|
{
|
|
public void OnActionExecuting(ActionExecutingContext filterContext)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void OnActionExecuted(ActionExecutedContext filterContext)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void OnResultExecuting(ResultExecutingContext filterContext)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void OnResultExecuted(ResultExecutedContext filterContext)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
private class ActionFilterImpl : IActionFilter, IResultFilter
|
|
{
|
|
public Action<ActionExecutingContext> OnActionExecutingImpl { get; set; }
|
|
|
|
public void OnActionExecuting(ActionExecutingContext filterContext)
|
|
{
|
|
OnActionExecutingImpl(filterContext);
|
|
}
|
|
|
|
public Action<ActionExecutedContext> OnActionExecutedImpl { get; set; }
|
|
|
|
public void OnActionExecuted(ActionExecutedContext filterContext)
|
|
{
|
|
OnActionExecutedImpl(filterContext);
|
|
}
|
|
|
|
public Action<ResultExecutingContext> OnResultExecutingImpl { get; set; }
|
|
|
|
public void OnResultExecuting(ResultExecutingContext filterContext)
|
|
{
|
|
OnResultExecutingImpl(filterContext);
|
|
}
|
|
|
|
public Action<ResultExecutedContext> OnResultExecutedImpl { get; set; }
|
|
|
|
public void OnResultExecuted(ResultExecutedContext filterContext)
|
|
{
|
|
OnResultExecutedImpl(filterContext);
|
|
}
|
|
}
|
|
|
|
[KeyedActionFilter(Key = "BaseClass", Order = 0)]
|
|
[KeyedAuthorizationFilter(Key = "BaseClass", Order = 0)]
|
|
private class GetMemberChainController : Controller
|
|
{
|
|
[KeyedActionFilter(Key = "BaseMethod", Order = 0)]
|
|
[KeyedAuthorizationFilter(Key = "BaseMethod", Order = 0)]
|
|
public virtual void SomeVirtual()
|
|
{
|
|
}
|
|
}
|
|
|
|
[KeyedActionFilter(Key = "DerivedClass", Order = 1)]
|
|
private class GetMemberChainDerivedController : GetMemberChainController
|
|
{
|
|
}
|
|
|
|
[KeyedActionFilter(Key = "SubderivedClass", Order = 2)]
|
|
private class GetMemberChainSubderivedController : GetMemberChainDerivedController
|
|
{
|
|
[KeyedActionFilter(Key = "SubderivedMethod", Order = 2)]
|
|
public override void SomeVirtual()
|
|
{
|
|
}
|
|
}
|
|
|
|
// This controller serves only to test vanilla method invocation - nothing exciting here
|
|
private class BasicMethodInvokeController : Controller
|
|
{
|
|
public ActionResult ReturnsRenderView(object viewItem)
|
|
{
|
|
return View("ReturnsRenderView", viewItem);
|
|
}
|
|
}
|
|
|
|
private class BlankController : Controller
|
|
{
|
|
}
|
|
|
|
private sealed class CustomResult : ActionResult
|
|
{
|
|
public object ReturnValue { get; set; }
|
|
|
|
public override void ExecuteResult(ControllerContext context)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
private sealed class CustomResultInvokerController : Controller
|
|
{
|
|
public object ReturnCustomResult()
|
|
{
|
|
return "abc123";
|
|
}
|
|
}
|
|
|
|
private sealed class CustomResultInvoker : ControllerActionInvokerHelper
|
|
{
|
|
protected override ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue)
|
|
{
|
|
return new CustomResult
|
|
{
|
|
ReturnValue = actionReturnValue
|
|
};
|
|
}
|
|
}
|
|
|
|
private class ContinuationController : Controller
|
|
{
|
|
private Func<ActionResult> _continuation;
|
|
|
|
public ContinuationController(Func<ActionResult> continuation)
|
|
{
|
|
_continuation = continuation;
|
|
}
|
|
|
|
public ActionResult Go()
|
|
{
|
|
return _continuation();
|
|
}
|
|
|
|
public static MethodInfo GoMethod
|
|
{
|
|
get { return typeof(ContinuationController).GetMethod("Go"); }
|
|
}
|
|
}
|
|
|
|
private class ContinuationResult : ActionResult
|
|
{
|
|
private Action _continuation;
|
|
|
|
public ContinuationResult(Action continuation)
|
|
{
|
|
_continuation = continuation;
|
|
}
|
|
|
|
public override void ExecuteResult(ControllerContext context)
|
|
{
|
|
_continuation();
|
|
}
|
|
}
|
|
|
|
private class EmptyController : Controller
|
|
{
|
|
}
|
|
|
|
// This controller serves to test the default action method matching mechanism
|
|
private class FindMethodController : Controller
|
|
{
|
|
public ActionResult ValidActionMethod()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
[NonAction]
|
|
public virtual ActionResult NonActionMethod()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
[NonAction]
|
|
public ActionResult DerivedIsActionMethod()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public ActionResult MethodOverloaded()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public ActionResult MethodOverloaded(string s)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public void WrongReturnType()
|
|
{
|
|
}
|
|
|
|
protected ActionResult ProtectedMethod()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
private ActionResult PrivateMethod()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
internal ActionResult InternalMethod()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
// originally defined on Object
|
|
return base.ToString();
|
|
}
|
|
|
|
public ActionResult Property
|
|
{
|
|
get { return null; }
|
|
}
|
|
|
|
#pragma warning disable 0067
|
|
// CS0067: Event declared but never used. We use reflection to access this member.
|
|
public event EventHandler Event;
|
|
#pragma warning restore 0067
|
|
}
|
|
|
|
private class DerivedFindMethodController : FindMethodController
|
|
{
|
|
public override ActionResult NonActionMethod()
|
|
{
|
|
return base.NonActionMethod();
|
|
}
|
|
|
|
// FindActionMethod() should accept this as a valid method since [NonAction] doesn't appear
|
|
// in its inheritance chain.
|
|
public new ActionResult DerivedIsActionMethod()
|
|
{
|
|
return base.DerivedIsActionMethod();
|
|
}
|
|
}
|
|
|
|
// Similar to FindMethodController, but tests generics support specifically
|
|
private class GenericFindMethodController<T> : Controller
|
|
{
|
|
public ActionResult ClosedGenericMethod(T t)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public ActionResult OpenGenericMethod<U>(U t)
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Allows for testing parameter conversions, etc.
|
|
private class ParameterTestingController : Controller
|
|
{
|
|
public ParameterTestingController()
|
|
{
|
|
Values = new Dictionary<string, object>();
|
|
}
|
|
|
|
public IDictionary<string, object> Values { get; private set; }
|
|
|
|
public void Foo(string foo, string bar, string baz)
|
|
{
|
|
Values["foo"] = foo;
|
|
Values["bar"] = bar;
|
|
Values["baz"] = baz;
|
|
}
|
|
|
|
public void HasOutParam(out string foo)
|
|
{
|
|
foo = null;
|
|
}
|
|
|
|
public void HasRefParam(ref string foo)
|
|
{
|
|
}
|
|
|
|
public void Parameterless()
|
|
{
|
|
}
|
|
|
|
public void TakesInt(int id)
|
|
{
|
|
Values["id"] = id;
|
|
}
|
|
|
|
public ActionResult TakesNullableInt(int? id)
|
|
{
|
|
Values["id"] = id;
|
|
return null;
|
|
}
|
|
|
|
public void TakesString(string id)
|
|
{
|
|
}
|
|
|
|
public void TakesDateTime(DateTime id)
|
|
{
|
|
}
|
|
}
|
|
|
|
// Provides access to the protected members of ControllerActionInvoker
|
|
public class ControllerActionInvokerHelper : ControllerActionInvoker
|
|
{
|
|
public ControllerActionInvokerHelper()
|
|
{
|
|
// set instance caches to prevent modifying global test application state
|
|
DescriptorCache = new ControllerDescriptorCache();
|
|
}
|
|
|
|
public ControllerActionInvokerHelper(params object[] filters)
|
|
: base(filters)
|
|
{
|
|
// set instance caches to prevent modifying global test application state
|
|
DescriptorCache = new ControllerDescriptorCache();
|
|
}
|
|
|
|
public virtual ActionResult PublicCreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue)
|
|
{
|
|
return base.CreateActionResult(controllerContext, actionDescriptor, actionReturnValue);
|
|
}
|
|
|
|
protected override ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue)
|
|
{
|
|
return PublicCreateActionResult(controllerContext, actionDescriptor, actionReturnValue);
|
|
}
|
|
|
|
public virtual ActionDescriptor PublicFindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
|
|
{
|
|
return base.FindAction(controllerContext, controllerDescriptor, actionName);
|
|
}
|
|
|
|
protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
|
|
{
|
|
return PublicFindAction(controllerContext, controllerDescriptor, actionName);
|
|
}
|
|
|
|
public virtual ControllerDescriptor PublicGetControllerDescriptor(ControllerContext controllerContext)
|
|
{
|
|
return base.GetControllerDescriptor(controllerContext);
|
|
}
|
|
|
|
protected override ControllerDescriptor GetControllerDescriptor(ControllerContext controllerContext)
|
|
{
|
|
return PublicGetControllerDescriptor(controllerContext);
|
|
}
|
|
|
|
public virtual FilterInfo PublicGetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
|
|
{
|
|
return base.GetFilters(controllerContext, actionDescriptor);
|
|
}
|
|
|
|
protected override FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
|
|
{
|
|
return PublicGetFilters(controllerContext, actionDescriptor);
|
|
}
|
|
|
|
public virtual object PublicGetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
|
|
{
|
|
return base.GetParameterValue(controllerContext, parameterDescriptor);
|
|
}
|
|
|
|
protected override object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
|
|
{
|
|
return PublicGetParameterValue(controllerContext, parameterDescriptor);
|
|
}
|
|
|
|
public virtual IDictionary<string, object> PublicGetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
|
|
{
|
|
return base.GetParameterValues(controllerContext, actionDescriptor);
|
|
}
|
|
|
|
protected override IDictionary<string, object> GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
|
|
{
|
|
return PublicGetParameterValues(controllerContext, actionDescriptor);
|
|
}
|
|
|
|
public virtual ActionResult PublicInvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
|
|
{
|
|
return base.InvokeActionMethod(controllerContext, actionDescriptor, parameters);
|
|
}
|
|
|
|
protected override ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
|
|
{
|
|
return PublicInvokeActionMethod(controllerContext, actionDescriptor, parameters);
|
|
}
|
|
|
|
public virtual ActionExecutedContext PublicInvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
|
|
{
|
|
return base.InvokeActionMethodWithFilters(controllerContext, filters, actionDescriptor, parameters);
|
|
}
|
|
|
|
protected override ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
|
|
{
|
|
return PublicInvokeActionMethodWithFilters(controllerContext, filters, actionDescriptor, parameters);
|
|
}
|
|
|
|
public virtual void PublicInvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
|
|
{
|
|
base.InvokeActionResult(controllerContext, actionResult);
|
|
}
|
|
|
|
protected override void InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
|
|
{
|
|
PublicInvokeActionResult(controllerContext, actionResult);
|
|
}
|
|
|
|
public virtual ResultExecutedContext PublicInvokeActionResultWithFilters(ControllerContext controllerContext, IList<IResultFilter> filters, ActionResult actionResult)
|
|
{
|
|
return base.InvokeActionResultWithFilters(controllerContext, filters, actionResult);
|
|
}
|
|
|
|
protected override ResultExecutedContext InvokeActionResultWithFilters(ControllerContext controllerContext, IList<IResultFilter> filters, ActionResult actionResult)
|
|
{
|
|
return PublicInvokeActionResultWithFilters(controllerContext, filters, actionResult);
|
|
}
|
|
|
|
public virtual AuthorizationContext PublicInvokeAuthorizationFilters(ControllerContext controllerContext, IList<IAuthorizationFilter> filters, ActionDescriptor actionDescriptor)
|
|
{
|
|
return base.InvokeAuthorizationFilters(controllerContext, filters, actionDescriptor);
|
|
}
|
|
|
|
protected override AuthorizationContext InvokeAuthorizationFilters(ControllerContext controllerContext, IList<IAuthorizationFilter> filters, ActionDescriptor actionDescriptor)
|
|
{
|
|
return PublicInvokeAuthorizationFilters(controllerContext, filters, actionDescriptor);
|
|
}
|
|
|
|
public virtual ExceptionContext PublicInvokeExceptionFilters(ControllerContext controllerContext, IList<IExceptionFilter> filters, Exception exception)
|
|
{
|
|
return base.InvokeExceptionFilters(controllerContext, filters, exception);
|
|
}
|
|
|
|
protected override ExceptionContext InvokeExceptionFilters(ControllerContext controllerContext, IList<IExceptionFilter> filters, Exception exception)
|
|
{
|
|
return PublicInvokeExceptionFilters(controllerContext, filters, exception);
|
|
}
|
|
}
|
|
|
|
public class AuthorizationFilterHelper : IAuthorizationFilter
|
|
{
|
|
private IList<AuthorizationFilterHelper> _callQueue;
|
|
public ActionResult ShortCircuitResult;
|
|
|
|
public AuthorizationFilterHelper(IList<AuthorizationFilterHelper> callQueue)
|
|
{
|
|
_callQueue = callQueue;
|
|
}
|
|
|
|
public void OnAuthorization(AuthorizationContext filterContext)
|
|
{
|
|
_callQueue.Add(this);
|
|
if (ShortCircuitResult != null)
|
|
{
|
|
filterContext.Result = ShortCircuitResult;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class ExceptionFilterHelper : IExceptionFilter
|
|
{
|
|
private IList<ExceptionFilterHelper> _callQueue;
|
|
public bool ShouldHandleException;
|
|
public ExceptionContext ContextPassed;
|
|
|
|
public ExceptionFilterHelper(IList<ExceptionFilterHelper> callQueue)
|
|
{
|
|
_callQueue = callQueue;
|
|
}
|
|
|
|
public void OnException(ExceptionContext filterContext)
|
|
{
|
|
_callQueue.Add(this);
|
|
if (ShouldHandleException)
|
|
{
|
|
filterContext.ExceptionHandled = true;
|
|
}
|
|
ContextPassed = filterContext;
|
|
}
|
|
}
|
|
|
|
private class CustomConverterController : Controller
|
|
{
|
|
public void ParameterWithoutBindAttribute([PredicateReflector] string someParam)
|
|
{
|
|
}
|
|
|
|
public void ParameterHasBindAttribute([Bind(Include = "foo"), PredicateReflector] string someParam)
|
|
{
|
|
}
|
|
|
|
public void ParameterHasDefaultValueAttribute([DefaultValue(42)] int foo)
|
|
{
|
|
}
|
|
|
|
public void ParameterHasFieldPrefix([Bind(Prefix = "bar")] string foo)
|
|
{
|
|
}
|
|
|
|
public void ParameterHasNullFieldPrefix([Bind(Include = "whatever")] string foo)
|
|
{
|
|
}
|
|
|
|
public void ParameterHasEmptyFieldPrefix([Bind(Prefix = "")] MySimpleModel foo)
|
|
{
|
|
}
|
|
|
|
public void ParameterHasNoPrefixAndComplexType(MySimpleModel foo)
|
|
{
|
|
}
|
|
|
|
public void ParameterHasPrefixAndComplexType([Bind(Prefix = "badprefix")] MySimpleModel foo)
|
|
{
|
|
}
|
|
|
|
public void ParameterHasNoConverters(string foo)
|
|
{
|
|
}
|
|
|
|
public void ParameterHasOneConverter([MyCustomConverter] string foo)
|
|
{
|
|
}
|
|
|
|
public void ParameterHasTwoConverters([MyCustomConverter, MyCustomConverter] string foo)
|
|
{
|
|
}
|
|
}
|
|
|
|
public class MySimpleModel
|
|
{
|
|
public int IntProp { get; set; }
|
|
public string StringProp { get; set; }
|
|
}
|
|
|
|
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = false)]
|
|
private class PredicateReflectorAttribute : CustomModelBinderAttribute
|
|
{
|
|
public override IModelBinder GetBinder()
|
|
{
|
|
return new MyConverter();
|
|
}
|
|
|
|
private class MyConverter : IModelBinder
|
|
{
|
|
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
|
|
{
|
|
string s = String.Format("foo={0}&bar={1}", bindingContext.PropertyFilter("foo"), bindingContext.PropertyFilter("bar"));
|
|
return s;
|
|
}
|
|
}
|
|
}
|
|
|
|
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = false)]
|
|
private class MyCustomConverterAttribute : CustomModelBinderAttribute
|
|
{
|
|
public override IModelBinder GetBinder()
|
|
{
|
|
return new MyConverter();
|
|
}
|
|
|
|
private class MyConverter : IModelBinder
|
|
{
|
|
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
|
|
{
|
|
string s = bindingContext.ModelName + "_" + bindingContext.ModelType.Name;
|
|
return s;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// helper class for making sure that we're performing culture-invariant string conversions
|
|
public class CultureReflector : IFormattable
|
|
{
|
|
string IFormattable.ToString(string format, IFormatProvider formatProvider)
|
|
{
|
|
CultureInfo cInfo = (CultureInfo)formatProvider;
|
|
return cInfo.ThreeLetterISOLanguageName;
|
|
}
|
|
}
|
|
}
|
|
}
|