PageRenderTime 64ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 1ms

/Test/SystemWebMvcTest/Mvc/Test/ControllerActionInvokerTest.cs

https://bitbucket.org/markhneedham/aspnet-mvc
C# | 2456 lines | 1785 code | 407 blank | 264 comment | 5 complexity | 4374b283754583dcd0ad6fd4d315596f MD5 | raw file
  1. namespace System.Web.Mvc.Test {
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Reflection;
  6. using System.Threading;
  7. using System.Web.Mvc;
  8. using System.Web.Routing;
  9. using System.Web.TestUtil;
  10. using Microsoft.VisualStudio.TestTools.UnitTesting;
  11. using Moq;
  12. [TestClass]
  13. [CLSCompliant(false)]
  14. public class ControllerActionInvokerTest {
  15. [TestMethod]
  16. public void FindActionMethodDoesNotMatchConstructor() {
  17. // FindActionMethod() shouldn't match special-named methods like type constructors.
  18. // Arrange
  19. var controller = new FindMethodController();
  20. ControllerContext context = GetControllerContext(controller);
  21. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  22. // Act
  23. MethodInfo mi = helper.PublicFindActionMethod(".ctor");
  24. // Assert
  25. Assert.IsNull(mi);
  26. }
  27. [TestMethod]
  28. public void FindActionMethodDoesNotMatchEvent() {
  29. // FindActionMethod() should skip methods that aren't publicly visible.
  30. // Arrange
  31. var controller = new FindMethodController();
  32. ControllerContext context = GetControllerContext(controller);
  33. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  34. // Act
  35. MethodInfo mi = helper.PublicFindActionMethod("add_Event");
  36. // Assert
  37. Assert.IsNull(mi);
  38. }
  39. [TestMethod]
  40. public void FindActionMethodDoesNotMatchInternalMethod() {
  41. // FindActionMethod() should skip methods that aren't publicly visible.
  42. // Arrange
  43. var controller = new FindMethodController();
  44. ControllerContext context = GetControllerContext(controller);
  45. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  46. // Act
  47. MethodInfo mi = helper.PublicFindActionMethod("InternalMethod");
  48. // Assert
  49. Assert.IsNull(mi);
  50. }
  51. [TestMethod]
  52. public void FindActionMethodDoesNotMatchMethodsDefinedOnControllerType() {
  53. // FindActionMethod() shouldn't match methods originally defined on the Controller type, e.g. Dispose().
  54. // Arrange
  55. var controller = new BlankController();
  56. ControllerContext context = GetControllerContext(controller);
  57. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  58. var methods = typeof(Controller).GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
  59. // Act & Assert
  60. foreach (var method in methods) {
  61. bool wasFound = true;
  62. try {
  63. MethodInfo mi = helper.PublicFindActionMethod(method.Name);
  64. wasFound = (mi != null);
  65. }
  66. finally {
  67. Assert.IsFalse(wasFound, "FindActionMethod() should return false for methods defined on the Controller class: " + method);
  68. }
  69. }
  70. }
  71. [TestMethod]
  72. public void FindActionMethodDoesNotMatchMethodsDefinedOnObjectType() {
  73. // FindActionMethod() shouldn't match methods originally defined on the Object type, e.g. ToString().
  74. // Arrange
  75. var controller = new FindMethodController();
  76. ControllerContext context = GetControllerContext(controller);
  77. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  78. // Act
  79. MethodInfo mi = helper.PublicFindActionMethod("ToString");
  80. // Assert
  81. Assert.IsNull(mi);
  82. }
  83. [TestMethod]
  84. public void FindActionMethodDoesNotMatchNonActionMethod() {
  85. // FindActionMethod() should respect the [NonAction] attribute.
  86. // Arrange
  87. var controller = new FindMethodController();
  88. ControllerContext context = GetControllerContext(controller);
  89. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  90. // Act
  91. MethodInfo mi = helper.PublicFindActionMethod("NonActionMethod");
  92. // Assert
  93. Assert.IsNull(mi);
  94. }
  95. [TestMethod]
  96. public void FindActionMethodDoesNotMatchOverriddenNonActionMethod() {
  97. // FindActionMethod() should trace the method's inheritance chain looking for the [NonAction] attribute.
  98. // Arrange
  99. var controller = new DerivedFindMethodController();
  100. ControllerContext context = GetControllerContext(controller);
  101. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  102. // Act
  103. MethodInfo mi = helper.PublicFindActionMethod("NonActionMethod");
  104. // Assert
  105. Assert.IsNull(mi);
  106. }
  107. [TestMethod]
  108. public void FindActionMethodDoesNotMatchPrivateMethod() {
  109. // FindActionMethod() should skip methods that aren't publicly visible.
  110. // Arrange
  111. var controller = new FindMethodController();
  112. ControllerContext context = GetControllerContext(controller);
  113. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  114. // Act
  115. MethodInfo mi = helper.PublicFindActionMethod("PrivateMethod");
  116. // Assert
  117. Assert.IsNull(mi);
  118. }
  119. [TestMethod]
  120. public void FindActionMethodDoesNotMatchProperty() {
  121. // FindActionMethod() shouldn't match special-named methods like property getters.
  122. // Arrange
  123. var controller = new FindMethodController();
  124. ControllerContext context = GetControllerContext(controller);
  125. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  126. // Act
  127. MethodInfo mi = helper.PublicFindActionMethod("get_Property");
  128. // Assert
  129. Assert.IsNull(mi);
  130. }
  131. [TestMethod]
  132. public void FindActionMethodDoesNotMatchProtectedMethod() {
  133. // FindActionMethod() should skip methods that aren't publicly visible.
  134. // Arrange
  135. var controller = new FindMethodController();
  136. ControllerContext context = GetControllerContext(controller);
  137. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  138. // Act
  139. MethodInfo mi = helper.PublicFindActionMethod("ProtectedMethod");
  140. // Assert
  141. Assert.IsNull(mi);
  142. }
  143. [TestMethod]
  144. public void FindActionMethodIsCaseInsensitive() {
  145. // Arrange
  146. var controller = new FindMethodController();
  147. ControllerContext context = GetControllerContext(controller);
  148. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  149. MethodInfo expected = typeof(FindMethodController).GetMethod("ValidActionMethod");
  150. // Act
  151. MethodInfo mi1 = helper.PublicFindActionMethod("validactionmethod");
  152. MethodInfo mi2 = helper.PublicFindActionMethod("VALIDACTIONMETHOD");
  153. // Assert
  154. Assert.AreEqual(expected, mi1);
  155. Assert.AreEqual(expected, mi2);
  156. }
  157. [TestMethod]
  158. public void FindActionMethodMatchesNewActionMethodsHidingNonActionMethods() {
  159. // FindActionMethod() should stop looking for [NonAction] in the method's inheritance chain when it sees
  160. // that a method in a derived class hides the a method in the base class.
  161. // Arrange
  162. var controller = new DerivedFindMethodController();
  163. ControllerContext context = GetControllerContext(controller);
  164. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  165. MethodInfo expected = typeof(DerivedFindMethodController).GetMethod("DerivedIsActionMethod");
  166. // Act
  167. MethodInfo mi = helper.PublicFindActionMethod("DerivedIsActionMethod");
  168. // Assert
  169. Assert.AreEqual(expected, mi);
  170. }
  171. [TestMethod]
  172. public void FindActionMethodWithClosedGenerics() {
  173. // FindActionMethod() should work with generic methods as long as there are no open types.
  174. // Arrange
  175. var controller = new GenericFindMethodController<int>();
  176. ControllerContext context = GetControllerContext(controller);
  177. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  178. MethodInfo expected = typeof(GenericFindMethodController<int>).GetMethod("ClosedGenericMethod");
  179. // Act
  180. MethodInfo mi = helper.PublicFindActionMethod("ClosedGenericMethod");
  181. // Assert
  182. Assert.AreEqual(expected, mi);
  183. }
  184. [TestMethod]
  185. public void FindActionMethodWithEmptyActionNameThrows() {
  186. // Arrange
  187. var controller = new FindMethodController();
  188. ControllerContext context = GetControllerContext(controller);
  189. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  190. // Act & Assert
  191. ExceptionHelper.ExpectArgumentExceptionNullOrEmpty(
  192. delegate {
  193. helper.PublicFindActionMethod(String.Empty);
  194. },
  195. "actionName");
  196. }
  197. [TestMethod]
  198. public void FindActionMethodWithNullActionNameThrows() {
  199. // Arrange
  200. var controller = new FindMethodController();
  201. ControllerContext context = GetControllerContext(controller);
  202. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  203. // Act & Assert
  204. ExceptionHelper.ExpectArgumentExceptionNullOrEmpty(
  205. delegate {
  206. helper.PublicFindActionMethod(null /* actionName */);
  207. },
  208. "actionName");
  209. }
  210. [TestMethod]
  211. public void FindActionMethodWithOpenGenericsThrows() {
  212. // FindActionMethod() should throw if matching on a generic method with open types.
  213. // Arrange
  214. var controller = new GenericFindMethodController<int>();
  215. ControllerContext context = GetControllerContext(controller);
  216. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  217. // Act & Assert
  218. ExceptionHelper.ExpectException<InvalidOperationException>(
  219. delegate {
  220. helper.PublicFindActionMethod("OpenGenericMethod");
  221. },
  222. "Cannot call action method 'System.Web.Mvc.ActionResult OpenGenericMethod[U](U)' since it is a generic method.");
  223. }
  224. [TestMethod]
  225. public void FindActionMethodWithOverloadsThrows() {
  226. // FindActionMethod() should throw if it encounters an overloaded method.
  227. // Arrange
  228. var controller = new FindMethodController();
  229. ControllerContext context = GetControllerContext(controller);
  230. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  231. // Act & Assert
  232. ExceptionHelper.ExpectException<InvalidOperationException>(
  233. delegate {
  234. helper.PublicFindActionMethod("MethodOverloaded");
  235. },
  236. @"The current request for action 'MethodOverloaded' on controller type 'FindMethodController' is ambiguous between the following action methods:
  237. System.Web.Mvc.ActionResult MethodOverloaded() on type System.Web.Mvc.Test.ControllerActionInvokerTest+FindMethodController
  238. System.Web.Mvc.ActionResult MethodOverloaded(System.String) on type System.Web.Mvc.Test.ControllerActionInvokerTest+FindMethodController");
  239. }
  240. [TestMethod]
  241. public void FindActionMethodWithValidMethod() {
  242. // Test basic functionality of FindActionMethod() by giving it a known good case.
  243. // Arrange
  244. var controller = new FindMethodController();
  245. ControllerContext context = GetControllerContext(controller);
  246. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  247. MethodInfo expected = typeof(FindMethodController).GetMethod("ValidActionMethod");
  248. // Act
  249. MethodInfo mi = helper.PublicFindActionMethod("ValidActionMethod");
  250. // Assert
  251. Assert.AreEqual(expected, mi);
  252. }
  253. [TestMethod]
  254. public void GetFiltersForActionMethod() {
  255. // Arrange
  256. ControllerBase controller = new GetMemberChainSubderivedController();
  257. ControllerContext context = GetControllerContext(controller);
  258. MethodInfo methodInfo = typeof(GetMemberChainSubderivedController).GetMethod("SomeVirtual");
  259. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  260. // Act
  261. var filters = helper.PublicGetFiltersForActionMethod(methodInfo);
  262. // Assert
  263. Assert.AreEqual(3, filters.AuthorizationFilters.Count, "Wrong number of authorization filters.");
  264. Assert.AreSame(controller, filters.AuthorizationFilters[0]);
  265. Assert.AreEqual("BaseClass", ((KeyedFilterAttribute)filters.AuthorizationFilters[1]).Key);
  266. Assert.AreEqual("BaseMethod", ((KeyedFilterAttribute)filters.AuthorizationFilters[2]).Key);
  267. Assert.AreEqual(6, filters.ActionFilters.Count, "Wrong number of action filters.");
  268. Assert.AreSame(controller, filters.ActionFilters[0]);
  269. Assert.AreEqual("BaseClass", ((KeyedFilterAttribute)filters.ActionFilters[1]).Key);
  270. Assert.AreEqual("BaseMethod", ((KeyedFilterAttribute)filters.ActionFilters[2]).Key);
  271. Assert.AreEqual("DerivedClass", ((KeyedFilterAttribute)filters.ActionFilters[3]).Key);
  272. Assert.AreEqual("SubderivedClass", ((KeyedFilterAttribute)filters.ActionFilters[4]).Key);
  273. Assert.AreEqual("SubderivedMethod", ((KeyedFilterAttribute)filters.ActionFilters[5]).Key);
  274. Assert.AreEqual(6, filters.ResultFilters.Count, "Wrong number of result filters.");
  275. Assert.AreSame(controller, filters.ResultFilters[0]);
  276. Assert.AreEqual("BaseClass", ((KeyedFilterAttribute)filters.ResultFilters[1]).Key);
  277. Assert.AreEqual("BaseMethod", ((KeyedFilterAttribute)filters.ResultFilters[2]).Key);
  278. Assert.AreEqual("DerivedClass", ((KeyedFilterAttribute)filters.ResultFilters[3]).Key);
  279. Assert.AreEqual("SubderivedClass", ((KeyedFilterAttribute)filters.ResultFilters[4]).Key);
  280. Assert.AreEqual("SubderivedMethod", ((KeyedFilterAttribute)filters.ResultFilters[5]).Key);
  281. Assert.AreEqual(1, filters.ExceptionFilters.Count, "Wrong number of exception filters.");
  282. Assert.AreSame(controller, filters.ExceptionFilters[0]);
  283. }
  284. [TestMethod]
  285. public void GetFiltersForActionMethodGetsDerivedClassFiltersForBaseClassMethod() {
  286. // DevDiv 208062: Action filters specified on derived class won't run if the action method is on a base class
  287. // Arrange
  288. ControllerBase controller = new GetMemberChainDerivedController();
  289. ControllerContext context = GetControllerContext(controller);
  290. MethodInfo methodInfo = typeof(GetMemberChainDerivedController).GetMethod("SomeVirtual");
  291. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  292. // Act
  293. var filters = helper.PublicGetFiltersForActionMethod(methodInfo);
  294. // Assert
  295. Assert.AreEqual(3, filters.AuthorizationFilters.Count, "Wrong number of authorization filters.");
  296. Assert.AreSame(controller, filters.AuthorizationFilters[0]);
  297. Assert.AreEqual("BaseClass", ((KeyedFilterAttribute)filters.AuthorizationFilters[1]).Key);
  298. Assert.AreEqual("BaseMethod", ((KeyedFilterAttribute)filters.AuthorizationFilters[2]).Key);
  299. Assert.AreEqual(4, filters.ActionFilters.Count, "Wrong number of action filters.");
  300. Assert.AreSame(controller, filters.ActionFilters[0]);
  301. Assert.AreEqual("BaseClass", ((KeyedFilterAttribute)filters.ActionFilters[1]).Key);
  302. Assert.AreEqual("BaseMethod", ((KeyedFilterAttribute)filters.ActionFilters[2]).Key);
  303. Assert.AreEqual("DerivedClass", ((KeyedFilterAttribute)filters.ActionFilters[3]).Key);
  304. Assert.AreEqual(4, filters.ResultFilters.Count, "Wrong number of result filters.");
  305. Assert.AreSame(controller, filters.ResultFilters[0]);
  306. Assert.AreEqual("BaseClass", ((KeyedFilterAttribute)filters.ResultFilters[1]).Key);
  307. Assert.AreEqual("BaseMethod", ((KeyedFilterAttribute)filters.ResultFilters[2]).Key);
  308. Assert.AreEqual("DerivedClass", ((KeyedFilterAttribute)filters.ResultFilters[3]).Key);
  309. Assert.AreEqual(1, filters.ExceptionFilters.Count, "Wrong number of exception filters.");
  310. Assert.AreSame(controller, filters.ExceptionFilters[0]);
  311. }
  312. [TestMethod]
  313. public void GetFiltersForActionMethodWithNullMethodInfoThrows() {
  314. // Arrange
  315. ControllerBase controller = new GetMemberChainSubderivedController();
  316. ControllerContext context = GetControllerContext(controller);
  317. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  318. // Act & Assert
  319. ExceptionHelper.ExpectArgumentNullException(
  320. delegate {
  321. helper.PublicGetFiltersForActionMethod(null /* methodInfo */);
  322. }, "methodInfo");
  323. }
  324. [TestMethod]
  325. public void GetParameterValueAllowsAllSubpropertiesIfBindAttributeNotSpecified() {
  326. // Arrange
  327. CustomConverterController controller = new CustomConverterController() { ValueProvider = new Mock<IValueProvider>().Object };
  328. ControllerContext controllerContext = GetControllerContext(controller);
  329. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(controllerContext);
  330. ParameterInfo paramWithoutBindAttribute = typeof(CustomConverterController).GetMethod("ParameterWithoutBindAttribute").GetParameters()[0];
  331. // Act
  332. object valueWithoutBindAttribute = helper.PublicGetParameterValue(paramWithoutBindAttribute);
  333. // Assert
  334. Assert.AreEqual("foo=True&bar=True", valueWithoutBindAttribute);
  335. }
  336. [TestMethod]
  337. public void GetParameterValueResolvesConvertersInCorrectOrderOfPrecedence() {
  338. // Order of precedence:
  339. // 1. Attributes on the parameter itself
  340. // 2. Query the global converter provider
  341. // Arrange
  342. CustomConverterController controller = new CustomConverterController();
  343. Dictionary<string, object> values = new Dictionary<string, object> { { "foo", "fooValue" } };
  344. ControllerContext controllerContext = GetControllerContext(controller, values);
  345. controller.ControllerContext = controllerContext;
  346. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(controllerContext);
  347. ParameterInfo paramWithOneConverter = typeof(CustomConverterController).GetMethod("ParameterHasOneConverter").GetParameters()[0];
  348. ParameterInfo paramWithNoConverters = typeof(CustomConverterController).GetMethod("ParameterHasNoConverters").GetParameters()[0];
  349. // Act
  350. object valueWithOneConverter = helper.PublicGetParameterValue(paramWithOneConverter);
  351. object valueWithNoConverters = helper.PublicGetParameterValue(paramWithNoConverters);
  352. // Assert
  353. Assert.AreEqual("foo_String", valueWithOneConverter);
  354. Assert.AreEqual("fooValue", valueWithNoConverters);
  355. }
  356. [TestMethod]
  357. public void GetParameterValueRespectsBindAttribute() {
  358. // Arrange
  359. CustomConverterController controller = new CustomConverterController() { ValueProvider = new Mock<IValueProvider>().Object };
  360. ControllerContext controllerContext = GetControllerContext(controller);
  361. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(controllerContext);
  362. ParameterInfo paramWithBindAttribute = typeof(CustomConverterController).GetMethod("ParameterHasBindAttribute").GetParameters()[0];
  363. // Act
  364. object valueWithBindAttribute = helper.PublicGetParameterValue(paramWithBindAttribute);
  365. // Assert
  366. Assert.AreEqual("foo=True&bar=False", valueWithBindAttribute);
  367. }
  368. [TestMethod]
  369. public void GetParameterValueRespectsBindAttributePrefix() {
  370. // Arrange
  371. CustomConverterController controller = new CustomConverterController();
  372. Dictionary<string, object> values = new Dictionary<string, object> { { "foo", "fooValue" }, { "bar", "barValue" } };
  373. ControllerContext controllerContext = GetControllerContext(controller, values);
  374. controller.ControllerContext = controllerContext;
  375. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(controllerContext);
  376. ParameterInfo paramWithFieldPrefix = typeof(CustomConverterController).GetMethod("ParameterHasFieldPrefix").GetParameters()[0];
  377. // Act
  378. object parameterValue = helper.PublicGetParameterValue(paramWithFieldPrefix);
  379. // Assert
  380. Assert.AreEqual("barValue", parameterValue);
  381. }
  382. [TestMethod]
  383. public void GetParameterValueRespectsBindAttributeNullPrefix() {
  384. // Arrange
  385. CustomConverterController controller = new CustomConverterController();
  386. Dictionary<string, object> values = new Dictionary<string, object> { { "foo", "fooValue" }, { "bar", "barValue" } };
  387. ControllerContext controllerContext = GetControllerContext(controller, values);
  388. controller.ControllerContext = controllerContext;
  389. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(controllerContext);
  390. ParameterInfo paramWithFieldPrefix = typeof(CustomConverterController).GetMethod("ParameterHasNullFieldPrefix").GetParameters()[0];
  391. // Act
  392. object parameterValue = helper.PublicGetParameterValue(paramWithFieldPrefix);
  393. // Assert
  394. Assert.AreEqual("fooValue", parameterValue);
  395. }
  396. [TestMethod]
  397. public void GetParameterValueRespectsBindAttributeEmptyPrefix() {
  398. // Arrange
  399. CustomConverterController controller = new CustomConverterController();
  400. Dictionary<string, object> values = new Dictionary<string, object> { { "foo", "fooValue" }, { "bar", "barValue" }, { "intprop", "123" }, { "stringprop", "hello" } };
  401. ControllerContext controllerContext = GetControllerContext(controller, values);
  402. controller.ControllerContext = controllerContext;
  403. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(controllerContext);
  404. ParameterInfo paramWithFieldPrefix = typeof(CustomConverterController).GetMethod("ParameterHasEmptyFieldPrefix").GetParameters()[0];
  405. // Act
  406. MySimpleModel parameterValue = helper.PublicGetParameterValue(paramWithFieldPrefix) as MySimpleModel;
  407. // Assert
  408. Assert.IsNotNull(parameterValue);
  409. Assert.AreEqual<int>(123, parameterValue.IntProp);
  410. Assert.AreEqual<string>("hello", parameterValue.StringProp);
  411. }
  412. [TestMethod]
  413. public void GetParameterValueReturnsNullIfCannotConvertNonRequiredParameter() {
  414. // Arrange
  415. var controller = new ParameterTestingController();
  416. ControllerContext context = GetControllerContext(controller);
  417. controller.ControllerContext = context;
  418. Dictionary<string, object> dict = new Dictionary<string, object>() {
  419. { "id", DateTime.Now } // cannot convert DateTime to Nullable<int>
  420. };
  421. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  422. MethodInfo mi = typeof(ParameterTestingController).GetMethod("TakesNullableInt");
  423. ParameterInfo[] pis = mi.GetParameters();
  424. // Act
  425. object oValue = helper.PublicGetParameterValue(pis[0]);
  426. // Assert
  427. Assert.IsNull(oValue);
  428. }
  429. [TestMethod]
  430. public void GetParameterValueReturnsNullIfNullableTypeValueNotFound() {
  431. // Arrange
  432. var controller = new ParameterTestingController();
  433. ControllerContext context = GetControllerContext(controller);
  434. controller.ControllerContext = context;
  435. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  436. MethodInfo mi = typeof(ParameterTestingController).GetMethod("TakesNullableInt");
  437. ParameterInfo[] pis = mi.GetParameters();
  438. // Act
  439. object oValue = helper.PublicGetParameterValue(pis[0]);
  440. // Assert
  441. Assert.IsNull(oValue);
  442. }
  443. [TestMethod]
  444. public void GetParameterValueReturnsNullIfReferenceTypeValueNotFound() {
  445. // Arrange
  446. var controller = new ParameterTestingController();
  447. ControllerContext context = GetControllerContext(controller);
  448. controller.ControllerContext = context;
  449. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  450. MethodInfo mi = typeof(ParameterTestingController).GetMethod("Foo");
  451. ParameterInfo[] pis = mi.GetParameters();
  452. // Act
  453. object oValue = helper.PublicGetParameterValue(pis[0]);
  454. // Assert
  455. Assert.IsNull(oValue);
  456. }
  457. [TestMethod]
  458. public void GetParameterValuesCallsGetParameterValue() {
  459. // Arrange
  460. ControllerBase controller = new ParameterTestingController();
  461. IDictionary<string, object> dict = new Dictionary<string, object>();
  462. ControllerContext context = GetControllerContext(controller);
  463. MethodInfo mi = typeof(ParameterTestingController).GetMethod("Foo");
  464. ParameterInfo[] pis = mi.GetParameters();
  465. Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>(context);
  466. mockHelper.CallBase = true;
  467. mockHelper.Expect(h => h.PublicGetParameterValue(pis[0])).Returns("Myfoo").Verifiable();
  468. mockHelper.Expect(h => h.PublicGetParameterValue(pis[1])).Returns("Mybar").Verifiable();
  469. mockHelper.Expect(h => h.PublicGetParameterValue(pis[2])).Returns("Mybaz").Verifiable();
  470. ControllerActionInvokerHelper helper = mockHelper.Object;
  471. // Act
  472. IDictionary<string, object> parameters = helper.PublicGetParameterValues(mi);
  473. // Assert
  474. Assert.AreEqual(3, parameters.Count);
  475. Assert.AreEqual("Myfoo", parameters["foo"]);
  476. Assert.AreEqual("Mybar", parameters["bar"]);
  477. Assert.AreEqual("Mybaz", parameters["baz"]);
  478. mockHelper.Verify();
  479. }
  480. [TestMethod]
  481. public void GetParameterValuesReturnsEmptyArrayForParameterlessMethod() {
  482. // Arrange
  483. var controller = new ParameterTestingController();
  484. ControllerContext context = GetControllerContext(controller);
  485. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  486. MethodInfo mi = typeof(ParameterTestingController).GetMethod("Parameterless");
  487. // Act
  488. IDictionary<string, object> parameters = helper.PublicGetParameterValues(mi);
  489. // Assert
  490. Assert.AreEqual(0, parameters.Count);
  491. }
  492. [TestMethod]
  493. public void GetParameterValuesReturnsValuesForParametersInOrder() {
  494. // We need to hook into GetParameterValue() to make sure that GetParameterValues() is calling it.
  495. // Arrange
  496. var controller = new ParameterTestingController();
  497. Dictionary<string, object> dict = new Dictionary<string, object>() {
  498. { "foo", "MyFoo" },
  499. { "bar", "MyBar" },
  500. { "baz", "MyBaz" }
  501. };
  502. ControllerContext context = GetControllerContext(controller, dict);
  503. controller.ControllerContext = context;
  504. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  505. MethodInfo mi = typeof(ParameterTestingController).GetMethod("Foo");
  506. // Act
  507. IDictionary<string, object> parameters = helper.PublicGetParameterValues(mi);
  508. // Assert
  509. Assert.AreEqual(3, parameters.Count);
  510. Assert.AreEqual("MyFoo", parameters["foo"]);
  511. Assert.AreEqual("MyBar", parameters["bar"]);
  512. Assert.AreEqual("MyBaz", parameters["baz"]);
  513. }
  514. [TestMethod]
  515. public void GetParameterValuesWithNullMethodInfoThrows() {
  516. // Arrange
  517. var controller = new ParameterTestingController();
  518. ControllerContext context = GetControllerContext(controller);
  519. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  520. // Act & Assert
  521. ExceptionHelper.ExpectArgumentNullException(
  522. delegate {
  523. helper.PublicGetParameterValues(null /* methodInfo */);
  524. },
  525. "methodInfo");
  526. }
  527. [TestMethod]
  528. public void GetParameterValuesWithOutParamThrows() {
  529. // Arrange
  530. var controller = new ParameterTestingController();
  531. ControllerContext context = GetControllerContext(controller);
  532. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  533. MethodInfo mi = typeof(ParameterTestingController).GetMethod("HasOutParam");
  534. // Act & Assert
  535. ExceptionHelper.ExpectException<InvalidOperationException>(
  536. delegate {
  537. helper.PublicGetParameterValues(mi);
  538. },
  539. "Cannot set value for parameter 'foo' in action 'HasOutParam'. Parameters passed by reference are not supported in action methods.");
  540. }
  541. [TestMethod]
  542. public void GetParameterValuesWithRefParamThrows() {
  543. // Arrange
  544. var controller = new ParameterTestingController();
  545. ControllerContext context = GetControllerContext(controller);
  546. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  547. MethodInfo mi = typeof(ParameterTestingController).GetMethod("HasRefParam");
  548. // Act & Assert
  549. ExceptionHelper.ExpectException<InvalidOperationException>(
  550. delegate {
  551. helper.PublicGetParameterValues(mi);
  552. },
  553. "Cannot set value for parameter 'foo' in action 'HasRefParam'. Parameters passed by reference are not supported in action methods.");
  554. }
  555. // TODO: This test is temporarily disabled now that converters can update ModelState. We should consider reenabling
  556. // this if invalid inputs to action methods become problematic.
  557. public void GetParameterValueThrowsIfCannotConvertRequiredParameter() {
  558. // Arrange
  559. var controller = new ParameterTestingController();
  560. ControllerContext context = GetControllerContext(controller);
  561. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  562. MethodInfo mi = typeof(ParameterTestingController).GetMethod("TakesInt");
  563. ParameterInfo[] pis = mi.GetParameters();
  564. // Act & Assert
  565. ExceptionHelper.ExpectInvalidOperationException(
  566. delegate {
  567. helper.PublicGetParameterValue(pis[0]);
  568. },
  569. "A value is required for parameter 'id' in action 'TakesInt'. The parameter either has no value or its value could"
  570. + " not be converted. To make a parameter optional its type should either be a reference type or a Nullable type.");
  571. }
  572. [TestMethod]
  573. public void GetParameterValueThrowsIfParameterHasMultipleConverters() {
  574. // Arrange
  575. CustomConverterController controller = new CustomConverterController();
  576. ControllerContext controllerContext = GetControllerContext(controller);
  577. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(controllerContext);
  578. ParameterInfo paramWithTwoConverters = typeof(CustomConverterController).GetMethod("ParameterHasTwoConverters").GetParameters()[0];
  579. // Act & Assert
  580. ExceptionHelper.ExpectInvalidOperationException(
  581. delegate {
  582. helper.PublicGetParameterValue(paramWithTwoConverters);
  583. },
  584. "The parameter 'foo' on method 'ParameterHasTwoConverters' contains multiple attributes inheriting from CustomModelBinderAttribute.");
  585. }
  586. [TestMethod]
  587. public void GetParameterValueUsesControllerValueProviderAsValueProvider() {
  588. // Arrange
  589. Mock<IValueProvider> mockValueProvider = new Mock<IValueProvider>();
  590. mockValueProvider.Expect(p => p.GetValue("foo")).Returns(new ValueProviderResult("fooValue", "fooValue", null));
  591. CustomConverterController controller = new CustomConverterController() { ValueProvider = mockValueProvider.Object };
  592. ControllerContext controllerContext = GetControllerContext(controller);
  593. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(controllerContext);
  594. ParameterInfo parameter = typeof(CustomConverterController).GetMethod("ParameterHasNoConverters").GetParameters()[0];
  595. // Act
  596. object parameterValue = helper.PublicGetParameterValue(parameter);
  597. // Assert
  598. Assert.AreEqual("fooValue", parameterValue);
  599. }
  600. [TestMethod]
  601. public void GetParameterValueWithNullParameterInfoThrows() {
  602. // Arrange
  603. var controller = new ParameterTestingController();
  604. ControllerContext context = GetControllerContext(controller);
  605. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  606. // Act & Assert
  607. ExceptionHelper.ExpectArgumentNullException(
  608. delegate {
  609. helper.PublicGetParameterValue(null /* parameterInfo */);
  610. },
  611. "parameterInfo");
  612. }
  613. [TestMethod]
  614. public void InvokeAction() {
  615. // Arrange
  616. ControllerBase controller = new Mock<ControllerBase>().Object;
  617. ControllerContext context = GetControllerContext(controller);
  618. IDictionary<string, object> paramValues = new Dictionary<string, object>();
  619. MethodInfo methodInfo = typeof(object).GetMethod("ToString");
  620. var filterInfo = new FilterInfo();
  621. ActionResult actionResult = new EmptyResult();
  622. ActionExecutedContext postContext = new ActionExecutedContext(context, false /* canceled */, null /* exception */) {
  623. Result = actionResult
  624. };
  625. AuthorizationContext authContext = new AuthorizationContext(context);
  626. Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>();
  627. mockHelper.CallBase = true;
  628. mockHelper.Expect(h => h.PublicFindActionMethod("SomeMethod")).Returns(methodInfo).Verifiable();
  629. mockHelper.Expect(h => h.PublicGetParameterValues(methodInfo)).Returns(paramValues).Verifiable();
  630. mockHelper.Expect(h => h.PublicGetFiltersForActionMethod(methodInfo)).Returns(filterInfo).Verifiable();
  631. mockHelper.Expect(h => h.PublicInvokeAuthorizationFilters(methodInfo, filterInfo.AuthorizationFilters)).Returns(authContext).Verifiable();
  632. mockHelper.Expect(h => h.PublicInvokeActionMethodWithFilters(methodInfo, paramValues, filterInfo.ActionFilters)).Returns(postContext).Verifiable();
  633. mockHelper.Expect(h => h.PublicInvokeActionResultWithFilters(actionResult, filterInfo.ResultFilters)).Returns((ResultExecutedContext)null).Verifiable();
  634. ControllerActionInvokerHelper helper = mockHelper.Object;
  635. // Act
  636. bool retVal = helper.InvokeAction(context, "SomeMethod");
  637. Assert.IsTrue(retVal, "InvokeAction() should return True on success.");
  638. Assert.AreSame(context, helper.ControllerContext, "ControllerContext property should have been set by InvokeAction");
  639. mockHelper.Verify();
  640. }
  641. [TestMethod]
  642. public void InvokeActionFiltersOrdersFiltersCorrectly() {
  643. // Arrange
  644. List<string> actions = new List<string>();
  645. Dictionary<string, object> parameters = new Dictionary<string, object>();
  646. ActionResult actionResult = new EmptyResult();
  647. ActionFilterImpl filter1 = new ActionFilterImpl() {
  648. OnActionExecutingImpl = delegate(ActionExecutingContext filterContext) {
  649. actions.Add("OnActionExecuting1");
  650. },
  651. OnActionExecutedImpl = delegate(ActionExecutedContext filterContext) {
  652. actions.Add("OnActionExecuted1");
  653. }
  654. };
  655. ActionFilterImpl filter2 = new ActionFilterImpl() {
  656. OnActionExecutingImpl = delegate(ActionExecutingContext filterContext) {
  657. actions.Add("OnActionExecuting2");
  658. },
  659. OnActionExecutedImpl = delegate(ActionExecutedContext filterContext) {
  660. actions.Add("OnActionExecuted2");
  661. }
  662. };
  663. Func<ActionResult> continuation = delegate {
  664. actions.Add("Continuation");
  665. return new EmptyResult();
  666. };
  667. ControllerBase controller = new ContinuationController(continuation);
  668. ControllerContext context = GetControllerContext(controller);
  669. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  670. // Act
  671. helper.PublicInvokeActionMethodWithFilters(ContinuationController.GoMethod, parameters,
  672. new List<IActionFilter>() { filter1, filter2 });
  673. // Assert
  674. Assert.AreEqual(5, actions.Count);
  675. Assert.AreEqual("OnActionExecuting1", actions[0]);
  676. Assert.AreEqual("OnActionExecuting2", actions[1]);
  677. Assert.AreEqual("Continuation", actions[2]);
  678. Assert.AreEqual("OnActionExecuted2", actions[3]);
  679. Assert.AreEqual("OnActionExecuted1", actions[4]);
  680. }
  681. [TestMethod]
  682. public void InvokeActionFiltersPassesArgumentsCorrectly() {
  683. // Arrange
  684. bool wasCalled = false;
  685. MethodInfo mi = ContinuationController.GoMethod;
  686. Dictionary<string, object> parameters = new Dictionary<string, object>();
  687. ActionResult actionResult = new EmptyResult();
  688. ActionFilterImpl filter = new ActionFilterImpl() {
  689. OnActionExecutingImpl = delegate(ActionExecutingContext filterContext) {
  690. Assert.AreSame(parameters, filterContext.ActionParameters);
  691. Assert.IsFalse(wasCalled);
  692. wasCalled = true;
  693. filterContext.Result = actionResult;
  694. }
  695. };
  696. Func<ActionResult> continuation = delegate {
  697. Assert.Fail("Continuation should not be called.");
  698. return null;
  699. };
  700. ControllerBase controller = new ContinuationController(continuation);
  701. ControllerContext context = GetControllerContext(controller);
  702. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  703. // Act
  704. ActionExecutedContext result = helper.PublicInvokeActionMethodWithFilters(mi, parameters,
  705. new List<IActionFilter>() { filter });
  706. // Assert
  707. Assert.IsTrue(wasCalled);
  708. Assert.IsNull(result.Exception);
  709. Assert.IsFalse(result.ExceptionHandled);
  710. Assert.AreSame(actionResult, result.Result);
  711. }
  712. [TestMethod]
  713. public void InvokeActionFilterWhereContinuationThrowsExceptionAndIsHandled() {
  714. // Arrange
  715. List<string> actions = new List<string>();
  716. MethodInfo mi = typeof(object).GetMethod("ToString");
  717. Dictionary<string, object> parameters = new Dictionary<string, object>();
  718. Exception exception = new Exception();
  719. ActionFilterImpl filter = new ActionFilterImpl() {
  720. OnActionExecutingImpl = delegate(ActionExecutingContext filterContext) {
  721. actions.Add("OnActionExecuting");
  722. },
  723. OnActionExecutedImpl = delegate(ActionExecutedContext filterContext) {
  724. actions.Add("OnActionExecuted");
  725. Assert.AreSame(exception, filterContext.Exception);
  726. Assert.IsFalse(filterContext.ExceptionHandled);
  727. filterContext.ExceptionHandled = true;
  728. }
  729. };
  730. Func<ActionExecutedContext> continuation = delegate {
  731. actions.Add("Continuation");
  732. throw exception;
  733. };
  734. // Act
  735. ActionExecutedContext result = ControllerActionInvoker.InvokeActionMethodFilter(filter, new ActionExecutingContext(ControllerContextTest.GetControllerContext(), parameters), continuation);
  736. // Assert
  737. Assert.AreEqual(3, actions.Count);
  738. Assert.AreEqual("OnActionExecuting", actions[0]);
  739. Assert.AreEqual("Continuation", actions[1]);
  740. Assert.AreEqual("OnActionExecuted", actions[2]);
  741. Assert.AreSame(exception, result.Exception);
  742. Assert.IsTrue(result.ExceptionHandled);
  743. }
  744. [TestMethod]
  745. public void InvokeActionFilterWhereContinuationThrowsExceptionAndIsNotHandled() {
  746. // Arrange
  747. List<string> actions = new List<string>();
  748. Dictionary<string, object> parameters = new Dictionary<string, object>();
  749. ActionFilterImpl filter = new ActionFilterImpl() {
  750. OnActionExecutingImpl = delegate(ActionExecutingContext filterContext) {
  751. actions.Add("OnActionExecuting");
  752. },
  753. OnActionExecutedImpl = delegate(ActionExecutedContext filterContext) {
  754. actions.Add("OnActionExecuted");
  755. }
  756. };
  757. Func<ActionExecutedContext> continuation = delegate {
  758. actions.Add("Continuation");
  759. throw new Exception("Some exception message.");
  760. };
  761. // Act & Assert
  762. ExceptionHelper.ExpectException<Exception>(
  763. delegate {
  764. ControllerActionInvoker.InvokeActionMethodFilter(filter, new ActionExecutingContext(ControllerContextTest.GetControllerContext(), parameters), continuation);
  765. },
  766. "Some exception message.");
  767. Assert.AreEqual(3, actions.Count);
  768. Assert.AreEqual("OnActionExecuting", actions[0]);
  769. Assert.AreEqual("Continuation", actions[1]);
  770. Assert.AreEqual("OnActionExecuted", actions[2]);
  771. }
  772. [TestMethod]
  773. public void InvokeActionFilterWhereOnActionExecutingCancels() {
  774. // Arrange
  775. bool wasCalled = false;
  776. Dictionary<string, object> parameters = new Dictionary<string, object>();
  777. ActionExecutedContext postContext = new ActionExecutedContext(ControllerContextTest.GetControllerContext(), false /* canceled */, null /* exception */);
  778. ActionResult actionResult = new EmptyResult();
  779. ActionFilterImpl filter = new ActionFilterImpl() {
  780. OnActionExecutingImpl = delegate(ActionExecutingContext filterContext) {
  781. Assert.IsFalse(wasCalled);
  782. wasCalled = true;
  783. filterContext.Result = actionResult;
  784. },
  785. };
  786. Func<ActionExecutedContext> continuation = delegate {
  787. Assert.Fail("The continuation should not be called.");
  788. return null;
  789. };
  790. // Act
  791. ActionExecutedContext result = ControllerActionInvoker.InvokeActionMethodFilter(filter, new ActionExecutingContext(ControllerContextTest.GetControllerContext(), parameters), continuation);
  792. // Assert
  793. Assert.IsTrue(wasCalled);
  794. Assert.IsNull(result.Exception);
  795. Assert.IsTrue(result.Canceled);
  796. Assert.AreSame(actionResult, result.Result);
  797. }
  798. [TestMethod]
  799. public void InvokeActionFilterWithNormalControlFlow() {
  800. // Arrange
  801. List<string> actions = new List<string>();
  802. Dictionary<string, object> parameters = new Dictionary<string, object>();
  803. ActionExecutedContext postContext = new ActionExecutedContext(ControllerContextTest.GetControllerContext(), false /* canceled */, null /* exception */);
  804. ActionFilterImpl filter = new ActionFilterImpl() {
  805. OnActionExecutingImpl = delegate(ActionExecutingContext filterContext) {
  806. Assert.AreSame(parameters, filterContext.ActionParameters);
  807. Assert.IsNull(filterContext.Result);
  808. actions.Add("OnActionExecuting");
  809. },
  810. OnActionExecutedImpl = delegate(ActionExecutedContext filterContext) {
  811. Assert.AreEqual(postContext, filterContext);
  812. actions.Add("OnActionExecuted");
  813. }
  814. };
  815. Func<ActionExecutedContext> continuation = delegate {
  816. actions.Add("Continuation");
  817. return postContext;
  818. };
  819. // Act
  820. ActionExecutedContext result = ControllerActionInvoker.InvokeActionMethodFilter(filter, new ActionExecutingContext(ControllerContextTest.GetControllerContext(), parameters), continuation);
  821. // Assert
  822. Assert.AreEqual(3, actions.Count);
  823. Assert.AreEqual("OnActionExecuting", actions[0]);
  824. Assert.AreEqual("Continuation", actions[1]);
  825. Assert.AreEqual("OnActionExecuted", actions[2]);
  826. Assert.AreSame(result, postContext);
  827. }
  828. [TestMethod]
  829. public void InvokeActionInvokesEmptyResultIfAuthorizationFailsAndNoResultSpecified() {
  830. // Arrange
  831. ControllerBase controller = new Mock<ControllerBase>().Object;
  832. ControllerContext context = GetControllerContext(controller);
  833. IDictionary<string, object> values = new Dictionary<string, object>();
  834. IDictionary<string, object> paramValues = new Dictionary<string, object>();
  835. MethodInfo methodInfo = typeof(object).GetMethod("ToString");
  836. var filterInfo = new FilterInfo();
  837. ActionResult actionResult = new EmptyResult();
  838. ActionExecutedContext postContext = new ActionExecutedContext(context, false /* canceled */, null /* exception */) {
  839. Result = actionResult
  840. };
  841. AuthorizationContext authContext = new AuthorizationContext(context) { Cancel = true };
  842. Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>();
  843. mockHelper.CallBase = true;
  844. mockHelper.Expect(h => h.PublicFindActionMethod("SomeMethod")).Returns(methodInfo).Verifiable();
  845. mockHelper.Expect(h => h.PublicGetParameterValues(methodInfo)).Returns(paramValues).Verifiable();
  846. mockHelper.Expect(h => h.PublicGetFiltersForActionMethod(methodInfo)).Returns(filterInfo).Verifiable();
  847. mockHelper.Expect(h => h.PublicInvokeAuthorizationFilters(methodInfo, filterInfo.AuthorizationFilters)).Returns(authContext).Verifiable();
  848. mockHelper.Expect(h => h.PublicInvokeActionResult(EmptyResult.Instance)).Verifiable();
  849. ControllerActionInvokerHelper helper = mockHelper.Object;
  850. // Act
  851. bool retVal = helper.InvokeAction(context, "SomeMethod");
  852. Assert.IsTrue(retVal, "InvokeAction() should return True on success.");
  853. mockHelper.Verify();
  854. }
  855. [TestMethod]
  856. public void InvokeActionInvokesExceptionFiltersAndExecutesResultIfExceptionHandled() {
  857. // Arrange
  858. ControllerBase controller = new Mock<ControllerBase>().Object;
  859. ControllerContext context = GetControllerContext(controller);
  860. IDictionary<string, object> values = new Dictionary<string, object>();
  861. IDictionary<string, object> paramValues = new Dictionary<string, object>();
  862. MethodInfo methodInfo = typeof(object).GetMethod("ToString");
  863. var filterInfo = new FilterInfo();
  864. Exception exception = new Exception();
  865. ActionResult actionResult = new EmptyResult();
  866. ExceptionContext exContext = new ExceptionContext(context, exception) {
  867. ExceptionHandled = true,
  868. Result = actionResult
  869. };
  870. Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>();
  871. mockHelper.CallBase = true;
  872. mockHelper.Expect(h => h.PublicFindActionMethod("SomeMethod")).Returns(methodInfo).Verifiable();
  873. mockHelper.Expect(h => h.PublicGetParameterValues(methodInfo)).Returns(paramValues).Verifiable();
  874. mockHelper.Expect(h => h.PublicGetFiltersForActionMethod(methodInfo)).Returns(filterInfo).Verifiable();
  875. mockHelper.Expect(h => h.PublicInvokeAuthorizationFilters(methodInfo, filterInfo.AuthorizationFilters)).Throws(exception).Verifiable();
  876. mockHelper.Expect(h => h.PublicInvokeExceptionFilters(exception, filterInfo.ExceptionFilters)).Returns(exContext).Verifiable();
  877. mockHelper.Expect(h => h.PublicInvokeActionResult(actionResult)).Verifiable();
  878. ControllerActionInvokerHelper helper = mockHelper.Object;
  879. // Act
  880. bool retVal = helper.InvokeAction(context, "SomeMethod");
  881. Assert.IsTrue(retVal, "InvokeAction() should return True on success.");
  882. mockHelper.Verify();
  883. }
  884. [TestMethod]
  885. public void InvokeActionInvokesExceptionFiltersAndRethrowsExceptionIfNotHandled() {
  886. // Arrange
  887. var controllerMock = new Mock<ControllerBase>();
  888. controllerMock.CallBase = true;
  889. ControllerBase controller = controllerMock.Object;
  890. ControllerContext context = GetControllerContext(controller);
  891. IDictionary<string, object> values = new Dictionary<string, object>();
  892. IDictionary<string, object> paramValues = new Dictionary<string, object>();
  893. MethodInfo methodInfo = typeof(object).GetMethod("ToString");
  894. var filterInfo = new FilterInfo();
  895. Exception exception = new Exception();
  896. ExceptionContext exContext = new ExceptionContext(context, exception);
  897. Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>();
  898. mockHelper.CallBase = true;
  899. mockHelper.Expect(h => h.PublicFindActionMethod("SomeMethod")).Returns(methodInfo).Verifiable();
  900. mockHelper.Expect(h => h.PublicGetParameterValues(methodInfo)).Returns(paramValues).Verifiable();
  901. mockHelper.Expect(h => h.PublicGetFiltersForActionMethod(methodInfo)).Returns(filterInfo).Verifiable();
  902. mockHelper.Expect(h => h.PublicInvokeAuthorizationFilters(methodInfo, filterInfo.AuthorizationFilters)).Throws(exception).Verifiable();
  903. mockHelper.Expect(h => h.PublicInvokeExceptionFilters(exception, filterInfo.ExceptionFilters)).Returns(exContext).Verifiable();
  904. mockHelper.Expect(h => h.PublicInvokeActionResult(It.IsAny<ActionResult>())).Callback(delegate {
  905. Assert.Fail("InvokeActionResult() shouldn't be called if the exception was unhandled by filters.");
  906. });
  907. ControllerActionInvokerHelper helper = mockHelper.Object;
  908. // Act
  909. Exception thrownException = ExceptionHelper.ExpectException<Exception>(
  910. delegate {
  911. helper.InvokeAction(context, "SomeMethod");
  912. });
  913. // Assert
  914. Assert.AreSame(exception, thrownException);
  915. mockHelper.Verify();
  916. }
  917. [TestMethod]
  918. public void InvokeActionInvokesResultIfAuthorizationFails() {
  919. // Arrange
  920. var controllerMock = new Mock<ControllerBase> { CallBase = true };
  921. ControllerBase controller = controllerMock.Object;
  922. ControllerContext context = GetControllerContext(controller);
  923. IDictionary<string, object> values = new Dictionary<string, object>();
  924. IDictionary<string, object> paramValues = new Dictionary<string, object>();
  925. MethodInfo methodInfo = typeof(object).GetMethod("ToString");
  926. var filterInfo = new FilterInfo();
  927. ActionResult actionResult = new EmptyResult();
  928. ActionExecutedContext postContext = new ActionExecutedContext(context, false /* canceled */, null /* exception */) {
  929. Result = actionResult
  930. };
  931. AuthorizationContext authContext = new AuthorizationContext(context) { Cancel = true, Result = actionResult };
  932. Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>();
  933. mockHelper.CallBase = true;
  934. mockHelper.Expect(h => h.PublicFindActionMethod("SomeMethod")).Returns(methodInfo).Verifiable();
  935. mockHelper.Expect(h => h.PublicGetParameterValues(methodInfo)).Returns(paramValues).Verifiable();
  936. mockHelper.Expect(h => h.PublicGetFiltersForActionMethod(methodInfo)).Returns(filterInfo).Verifiable();
  937. mockHelper.Expect(h => h.PublicInvokeAuthorizationFilters(methodInfo, filterInfo.AuthorizationFilters)).Returns(authContext).Verifiable();
  938. mockHelper.Expect(h => h.PublicInvokeActionResult(actionResult)).Verifiable();
  939. ControllerActionInvokerHelper helper = mockHelper.Object;
  940. // Act
  941. bool retVal = helper.InvokeAction(context, "SomeMethod");
  942. Assert.IsTrue(retVal, "InvokeAction() should return True on success.");
  943. mockHelper.Verify();
  944. }
  945. [TestMethod]
  946. public void InvokeActionMethod() {
  947. // Arrange
  948. var controller = new BasicMethodInvokeController();
  949. ControllerContext context = GetControllerContext(controller);
  950. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  951. MethodInfo mi = typeof(BasicMethodInvokeController).GetMethod("ReturnsRenderView");
  952. object viewItem = new object();
  953. IDictionary<string, object> parameters = new Dictionary<string, object>() {
  954. { "viewItem", viewItem }
  955. };
  956. // Act
  957. ViewResult result = helper.PublicInvokeActionMethod(mi, parameters) as ViewResult;
  958. // Assert (arg got passed to method + back correctly)
  959. Assert.AreEqual("ReturnsRenderView", result.ViewName);
  960. Assert.AreSame(viewItem, result.ViewData.Model);
  961. }
  962. [TestMethod]
  963. public void InvokeActionMethodWithFiltersWithNullFilterListThrows() {
  964. // Arrange
  965. ControllerBase controller = new Mock<ControllerBase>().Object;
  966. ControllerContext context = GetControllerContext(controller);
  967. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  968. // Act & Assert
  969. ExceptionHelper.ExpectArgumentNullException(
  970. delegate {
  971. helper.PublicInvokeActionMethodWithFilters(typeof(object).GetMethod("ToString"), new Dictionary<string, object>(), null /* filters */);
  972. },
  973. "filters");
  974. }
  975. [TestMethod]
  976. public void InvokeActionMethodWithFiltersWithNullMethodInfoThrows() {
  977. // Arrange
  978. ControllerBase controller = new Mock<ControllerBase>().Object;
  979. ControllerContext context = GetControllerContext(controller);
  980. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  981. // Act & Assert
  982. ExceptionHelper.ExpectArgumentNullException(
  983. delegate {
  984. helper.PublicInvokeActionMethodWithFilters(null /* methodInfo */, null /* parameters */, null /* filters */);
  985. },
  986. "methodInfo");
  987. }
  988. [TestMethod]
  989. public void InvokeActionMethodWithFiltersWithNullParametersDictionaryThrows() {
  990. // Arrange
  991. ControllerBase controller = new Mock<ControllerBase>().Object;
  992. ControllerContext context = GetControllerContext(controller);
  993. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  994. // Act & Assert
  995. ExceptionHelper.ExpectArgumentNullException(
  996. delegate {
  997. helper.PublicInvokeActionMethodWithFilters(typeof(object).GetMethod("ToString"), null /* parameters */, null /* filters */);
  998. },
  999. "parameters");
  1000. }
  1001. [TestMethod]
  1002. public void InvokeActionMethodWithNullMethodInfoThrows() {
  1003. // Arrange
  1004. var controller = new BasicMethodInvokeController();
  1005. ControllerContext context = GetControllerContext(controller);
  1006. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  1007. // Act & Assert
  1008. ExceptionHelper.ExpectArgumentNullException(
  1009. delegate {
  1010. helper.PublicInvokeActionMethod(null /* methodInfo */, null);
  1011. },
  1012. "methodInfo");
  1013. }
  1014. [TestMethod]
  1015. public void InvokeActionMethodWithNullParametersDictionaryThrows() {
  1016. // Arrange
  1017. var controller = new BasicMethodInvokeController();
  1018. ControllerContext context = GetControllerContext(controller);
  1019. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  1020. MethodInfo mi = typeof(BasicMethodInvokeController).GetMethod("ReturnsRenderView");
  1021. // Act & Assert
  1022. ExceptionHelper.ExpectArgumentNullException(
  1023. delegate {
  1024. helper.PublicInvokeActionMethod(mi, null /* parameters */);
  1025. },
  1026. "parameters");
  1027. }
  1028. [TestMethod]
  1029. public void InvokeActionMethodWithParametersDictionaryContainingNullableType() {
  1030. // Arrange
  1031. var controller = new ParameterTestingController();
  1032. ControllerContext context = GetControllerContext(controller);
  1033. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  1034. MethodInfo mi = typeof(ParameterTestingController).GetMethod("TakesNullableInt");
  1035. Dictionary<string, object> parameters = new Dictionary<string, object>() {
  1036. { "id", null }
  1037. };
  1038. // Act
  1039. ActionResult result = helper.PublicInvokeActionMethod(mi, parameters);
  1040. // Assert
  1041. Assert.IsTrue(controller.Values.ContainsKey("id"));
  1042. Assert.IsNull(controller.Values["id"]);
  1043. }
  1044. [TestMethod]
  1045. public void InvokeActionMethodWithParametersDictionaryContainingNullValueTypeThrows() {
  1046. // Arrange
  1047. var controller = new ParameterTestingController();
  1048. ControllerContext context = GetControllerContext(controller);
  1049. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  1050. MethodInfo mi = typeof(ParameterTestingController).GetMethod("TakesInt");
  1051. Dictionary<string, object> parameters = new Dictionary<string, object>() {
  1052. { "id", null }
  1053. };
  1054. // Act & Assert
  1055. ExceptionHelper.ExpectException<InvalidOperationException>(
  1056. delegate {
  1057. helper.PublicInvokeActionMethod(mi, parameters);
  1058. },
  1059. "The parameters dictionary does not contain a valid value of type 'System.Int32' for parameter 'id'"
  1060. + " which is required for method 'Void TakesInt(Int32)' in 'System.Web.Mvc.Test.ControllerActionInvokerTest+ParameterTestingController'."
  1061. + " To make a parameter optional its type should either be a reference type or a Nullable type.");
  1062. }
  1063. [TestMethod]
  1064. public void InvokeActionMethodWithParametersDictionaryContainingWrongTypesThrows() {
  1065. // Arrange
  1066. var controller = new ParameterTestingController();
  1067. ControllerContext context = GetControllerContext(controller);
  1068. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  1069. MethodInfo mi = typeof(ParameterTestingController).GetMethod("TakesInt");
  1070. Dictionary<string, object> parameters = new Dictionary<string, object>() {
  1071. { "id", new object() }
  1072. };
  1073. // Act & Assert
  1074. ExceptionHelper.ExpectException<InvalidOperationException>(
  1075. delegate {
  1076. helper.PublicInvokeActionMethod(mi, parameters);
  1077. },
  1078. "The parameters dictionary does not contain a valid value of type 'System.Int32' for parameter 'id'"
  1079. + " which is required for method 'Void TakesInt(Int32)' in 'System.Web.Mvc.Test.ControllerActionInvokerTest+ParameterTestingController'."
  1080. + " To make a parameter optional its type should either be a reference type or a Nullable type.");
  1081. }
  1082. [TestMethod]
  1083. public void InvokeActionMethodWithParametersDictionaryMissingEntriesThrows() {
  1084. // Arrange
  1085. var controller = new ParameterTestingController();
  1086. ControllerContext context = GetControllerContext(controller);
  1087. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  1088. MethodInfo mi = typeof(ParameterTestingController).GetMethod("TakesInt");
  1089. Dictionary<string, object> parameters = new Dictionary<string, object>() {
  1090. { "foo", "bar" }
  1091. };
  1092. // Act & Assert
  1093. ExceptionHelper.ExpectException<InvalidOperationException>(
  1094. delegate {
  1095. helper.PublicInvokeActionMethod(mi, parameters);
  1096. },
  1097. "The parameters dictionary does not contain a valid value of type 'System.Int32' for parameter 'id'"
  1098. + " which is required for method 'Void TakesInt(Int32)' in 'System.Web.Mvc.Test.ControllerActionInvokerTest+ParameterTestingController'."
  1099. + " To make a parameter optional its type should either be a reference type or a Nullable type.");
  1100. }
  1101. [TestMethod]
  1102. public void InvokeActionMethodWithParametersDictionaryWrongLengthThrows() {
  1103. // Arrange
  1104. var controller = new BasicMethodInvokeController();
  1105. ControllerContext context = GetControllerContext(controller);
  1106. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  1107. MethodInfo mi = typeof(BasicMethodInvokeController).GetMethod("ReturnsRenderView");
  1108. Dictionary<string, object> parameters = new Dictionary<string, object>() {
  1109. { "foo", "bar" },
  1110. { "baz", "quux" }
  1111. };
  1112. // Act & Assert
  1113. ExceptionHelper.ExpectException<InvalidOperationException>(
  1114. delegate {
  1115. helper.PublicInvokeActionMethod(mi, parameters);
  1116. },
  1117. "The parameter dictionary contains an incorrect number of entries for method 'System.Web.Mvc.ActionResult ReturnsRenderView(System.Object)'.");
  1118. }
  1119. [TestMethod]
  1120. public void InvokeActionResultWithFiltersPassesSameContextObjectToInnerFilters() {
  1121. // Arrange
  1122. ResultExecutingContext storedContext = null;
  1123. ActionResult result = new EmptyResult();
  1124. List<IResultFilter> filters = new List<IResultFilter>() {
  1125. new ActionFilterImpl() {
  1126. OnResultExecutingImpl = delegate(ResultExecutingContext ctx) {
  1127. storedContext = ctx;
  1128. },
  1129. OnResultExecutedImpl = delegate { }
  1130. },
  1131. new ActionFilterImpl() {
  1132. OnResultExecutingImpl = delegate(ResultExecutingContext ctx) {
  1133. Assert.AreSame(storedContext, ctx);
  1134. },
  1135. OnResultExecutedImpl = delegate { }
  1136. },
  1137. };
  1138. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(GetControllerContext(new Mock<ControllerBase>().Object));
  1139. // Act
  1140. ResultExecutedContext postContext = helper.PublicInvokeActionResultWithFilters(result, filters);
  1141. // Assert
  1142. Assert.AreSame(result, postContext.Result);
  1143. }
  1144. [TestMethod]
  1145. public void InvokeActionResultWithFiltersWithNullActionResultThrows() {
  1146. // Arrange
  1147. ControllerBase controller = new Mock<ControllerBase>().Object;
  1148. ControllerContext context = GetControllerContext(controller);
  1149. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  1150. // Act & Assert
  1151. ExceptionHelper.ExpectArgumentNullException(
  1152. delegate {
  1153. helper.PublicInvokeActionResultWithFilters(null /* actionResult */, null /* filters */);
  1154. },
  1155. "actionResult");
  1156. }
  1157. [TestMethod]
  1158. public void InvokeActionResultWithFiltersWithNullFilterListThrows() {
  1159. // Arrange
  1160. ControllerBase controller = new Mock<ControllerBase>().Object;
  1161. ControllerContext context = GetControllerContext(controller);
  1162. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  1163. // Act & Assert
  1164. ExceptionHelper.ExpectArgumentNullException(
  1165. delegate {
  1166. helper.PublicInvokeActionResultWithFilters(new EmptyResult(), null /* filters */);
  1167. },
  1168. "filters");
  1169. }
  1170. [TestMethod]
  1171. public void InvokeActionResultWithNullActionResultThrows() {
  1172. // Arrange
  1173. ControllerBase controller = new Mock<ControllerBase>().Object;
  1174. ControllerContext context = GetControllerContext(controller);
  1175. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  1176. // Act & Assert
  1177. ExceptionHelper.ExpectArgumentNullException(
  1178. delegate {
  1179. helper.PublicInvokeActionResult(null /* actionResult */);
  1180. },
  1181. "actionResult");
  1182. }
  1183. [TestMethod]
  1184. public void InvokeActionReturnsFalseIfMethodNotFound() {
  1185. // Arrange
  1186. var controller = new BlankController();
  1187. ControllerContext context = GetControllerContext(controller);
  1188. ControllerActionInvoker invoker = new ControllerActionInvoker();
  1189. // Act
  1190. bool retVal = invoker.InvokeAction(context, "foo");
  1191. // Assert
  1192. Assert.IsFalse(retVal);
  1193. }
  1194. [TestMethod]
  1195. public void InvokeActionThrowsIfControllerContextIsNull() {
  1196. // Arrange
  1197. ControllerActionInvoker invoker = new ControllerActionInvoker();
  1198. // Act & Assert
  1199. ExceptionHelper.ExpectArgumentNullException(
  1200. delegate {
  1201. invoker.InvokeAction(null, "actionName");
  1202. }, "controllerContext");
  1203. }
  1204. [TestMethod]
  1205. public void InvokeActionWithEmptyActionNameThrows() {
  1206. // Arrange
  1207. var controller = new BasicMethodInvokeController();
  1208. ControllerContext context = GetControllerContext(controller);
  1209. ControllerActionInvoker invoker = new ControllerActionInvoker();
  1210. // Act & Assert
  1211. ExceptionHelper.ExpectArgumentExceptionNullOrEmpty(
  1212. delegate {
  1213. invoker.InvokeAction(context, String.Empty);
  1214. },
  1215. "actionName");
  1216. }
  1217. [TestMethod]
  1218. public void InvokeActionWithNullActionNameThrows() {
  1219. // Arrange
  1220. var controller = new BasicMethodInvokeController();
  1221. ControllerContext context = GetControllerContext(controller);
  1222. ControllerActionInvoker invoker = new ControllerActionInvoker();
  1223. // Act & Assert
  1224. ExceptionHelper.ExpectArgumentExceptionNullOrEmpty(
  1225. delegate {
  1226. invoker.InvokeAction(context, null /* actionName */);
  1227. },
  1228. "actionName");
  1229. }
  1230. [TestMethod]
  1231. public void InvokeActionWithResultExceptionInvokesExceptionFiltersAndExecutesResultIfExceptionHandled() {
  1232. // Arrange
  1233. ControllerBase controller = new Mock<ControllerBase>().Object;
  1234. ControllerContext context = GetControllerContext(controller);
  1235. IDictionary<string, object> values = new Dictionary<string, object>();
  1236. IDictionary<string, object> paramValues = new Dictionary<string, object>();
  1237. MethodInfo methodInfo = typeof(object).GetMethod("ToString");
  1238. var filterInfo = new FilterInfo();
  1239. Exception exception = new Exception();
  1240. ActionResult actionResult = new EmptyResult();
  1241. ActionExecutedContext postContext = new ActionExecutedContext(context, false /* canceled */, null /* exception */) {
  1242. Result = actionResult
  1243. };
  1244. ExceptionContext exContext = new ExceptionContext(context, exception) {
  1245. ExceptionHandled = true,
  1246. Result = actionResult
  1247. };
  1248. AuthorizationContext authContext = new AuthorizationContext(context);
  1249. Mock<ControllerActionInvokerHelper> mockHelper = new Mock<ControllerActionInvokerHelper>();
  1250. mockHelper.CallBase = true;
  1251. mockHelper.Expect(h => h.PublicFindActionMethod("SomeMethod")).Returns(methodInfo).Verifiable();
  1252. mockHelper.Expect(h => h.PublicGetParameterValues(methodInfo)).Returns(paramValues).Verifiable();
  1253. mockHelper.Expect(h => h.PublicGetFiltersForActionMethod(methodInfo)).Returns(filterInfo).Verifiable();
  1254. mockHelper.Expect(h => h.PublicInvokeAuthorizationFilters(methodInfo, filterInfo.AuthorizationFilters)).Returns(authContext).Verifiable();
  1255. mockHelper.Expect(h => h.PublicInvokeActionMethodWithFilters(methodInfo, paramValues, filterInfo.ActionFilters)).Returns(postContext).Verifiable();
  1256. mockHelper.Expect(h => h.PublicInvokeActionResultWithFilters(actionResult, filterInfo.ResultFilters)).Throws(exception).Verifiable();
  1257. mockHelper.Expect(h => h.PublicInvokeExceptionFilters(exception, filterInfo.ExceptionFilters)).Returns(exContext).Verifiable();
  1258. mockHelper.Expect(h => h.PublicInvokeActionResult(actionResult)).Verifiable();
  1259. ControllerActionInvokerHelper helper = mockHelper.Object;
  1260. // Act
  1261. bool retVal = helper.InvokeAction(context, "SomeMethod");
  1262. Assert.IsTrue(retVal, "InvokeAction() should return True on success.");
  1263. mockHelper.Verify();
  1264. }
  1265. [TestMethod]
  1266. public void InvokeAuthorizationFilters() {
  1267. // Arrange
  1268. ControllerBase controller = new Mock<ControllerBase>().Object;
  1269. MethodInfo methodInfo = typeof(object).GetMethod("ToString");
  1270. ControllerContext controllerContext = GetControllerContext(controller);
  1271. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(controllerContext);
  1272. List<AuthorizationFilterHelper> callQueue = new List<AuthorizationFilterHelper>();
  1273. AuthorizationFilterHelper filter1 = new AuthorizationFilterHelper(callQueue);
  1274. AuthorizationFilterHelper filter2 = new AuthorizationFilterHelper(callQueue);
  1275. // Act
  1276. AuthorizationContext postContext = helper.PublicInvokeAuthorizationFilters(methodInfo, new List<IAuthorizationFilter> { filter1, filter2 });
  1277. // Assert
  1278. Assert.AreEqual(2, callQueue.Count);
  1279. Assert.AreSame(filter1, callQueue[0]);
  1280. Assert.AreSame(filter2, callQueue[1]);
  1281. }
  1282. [TestMethod]
  1283. public void InvokeAuthorizationFiltersStopsExecutingIfResultProvided() {
  1284. // Arrange
  1285. ControllerBase controller = new Mock<ControllerBase>().Object;
  1286. MethodInfo methodInfo = typeof(object).GetMethod("ToString");
  1287. ControllerContext controllerContext = GetControllerContext(controller);
  1288. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(controllerContext);
  1289. ActionResult result = new EmptyResult();
  1290. List<AuthorizationFilterHelper> callQueue = new List<AuthorizationFilterHelper>();
  1291. AuthorizationFilterHelper filter1 = new AuthorizationFilterHelper(callQueue) { ShouldCancel = true, ShortCircuitResult = result };
  1292. AuthorizationFilterHelper filter2 = new AuthorizationFilterHelper(callQueue);
  1293. // Act
  1294. AuthorizationContext postContext = helper.PublicInvokeAuthorizationFilters(methodInfo, new List<IAuthorizationFilter> { filter1, filter2 });
  1295. // Assert
  1296. Assert.IsTrue(postContext.Cancel);
  1297. Assert.AreSame(result, postContext.Result);
  1298. Assert.AreEqual(1, callQueue.Count);
  1299. Assert.AreSame(filter1, callQueue[0]);
  1300. }
  1301. [TestMethod]
  1302. public void InvokeAuthorizationFiltersWithNullFiltersThrows() {
  1303. // Arrange
  1304. ControllerBase controller = new Mock<ControllerBase>().Object;
  1305. ControllerContext context = GetControllerContext(controller);
  1306. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  1307. // Act & Assert
  1308. ExceptionHelper.ExpectArgumentNullException(
  1309. delegate {
  1310. helper.PublicInvokeAuthorizationFilters(typeof(object).GetMethod("ToString"), null /* filters */);
  1311. }, "filters");
  1312. }
  1313. [TestMethod]
  1314. public void InvokeExceptionFiltersWithNullMethodInfoThrows() {
  1315. // Arrange
  1316. ControllerBase controller = new Mock<ControllerBase>().Object;
  1317. ControllerContext context = GetControllerContext(controller);
  1318. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  1319. // Act & Assert
  1320. ExceptionHelper.ExpectArgumentNullException(
  1321. delegate {
  1322. helper.PublicInvokeAuthorizationFilters(null /* methodInfo */, null /* filters */);
  1323. }, "methodInfo");
  1324. }
  1325. [TestMethod]
  1326. public void InvokeExceptionFilters() {
  1327. // Arrange
  1328. ControllerBase controller = new Mock<ControllerBase>().Object;
  1329. Exception exception = new Exception();
  1330. ControllerContext controllerContext = GetControllerContext(controller);
  1331. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(controllerContext);
  1332. List<ExceptionFilterHelper> callQueue = new List<ExceptionFilterHelper>();
  1333. ExceptionFilterHelper filter1 = new ExceptionFilterHelper(callQueue);
  1334. ExceptionFilterHelper filter2 = new ExceptionFilterHelper(callQueue);
  1335. // Act
  1336. ExceptionContext postContext = helper.PublicInvokeExceptionFilters(exception, new List<IExceptionFilter> { filter1, filter2 });
  1337. // Assert
  1338. Assert.AreSame(exception, postContext.Exception);
  1339. Assert.IsFalse(postContext.ExceptionHandled);
  1340. Assert.AreSame(filter1.ContextPassed, filter2.ContextPassed, "The same context should have been passed to each exception filter.");
  1341. Assert.AreEqual(2, callQueue.Count);
  1342. Assert.AreSame(filter1, callQueue[0]);
  1343. Assert.AreSame(filter2, callQueue[1]);
  1344. }
  1345. [TestMethod]
  1346. public void InvokeExceptionFiltersContinuesExecutingIfExceptionHandled() {
  1347. // Arrange
  1348. ControllerBase controller = new Mock<ControllerBase>().Object;
  1349. Exception exception = new Exception();
  1350. ControllerContext controllerContext = GetControllerContext(controller);
  1351. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(controllerContext);
  1352. List<ExceptionFilterHelper> callQueue = new List<ExceptionFilterHelper>();
  1353. ExceptionFilterHelper filter1 = new ExceptionFilterHelper(callQueue) { ShouldHandleException = true };
  1354. ExceptionFilterHelper filter2 = new ExceptionFilterHelper(callQueue);
  1355. // Act
  1356. ExceptionContext postContext = helper.PublicInvokeExceptionFilters(exception, new List<IExceptionFilter> { filter1, filter2 });
  1357. // Assert
  1358. Assert.AreSame(exception, postContext.Exception);
  1359. Assert.IsTrue(postContext.ExceptionHandled, "The exception should have been handled.");
  1360. Assert.AreSame(filter1.ContextPassed, filter2.ContextPassed, "The same context should have been passed to each exception filter.");
  1361. Assert.AreEqual(2, callQueue.Count);
  1362. Assert.AreSame(filter1, callQueue[0]);
  1363. Assert.AreSame(filter2, callQueue[1]);
  1364. }
  1365. [TestMethod]
  1366. public void InvokeExceptionFiltersWithNullExceptionThrows() {
  1367. // Arrange
  1368. ControllerBase controller = new Mock<ControllerBase>().Object;
  1369. ControllerContext context = GetControllerContext(controller);
  1370. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  1371. // Act & Assert
  1372. ExceptionHelper.ExpectArgumentNullException(
  1373. delegate {
  1374. helper.PublicInvokeExceptionFilters(null /* exception */, null /* filters */);
  1375. }, "exception");
  1376. }
  1377. [TestMethod]
  1378. public void InvokeExceptionFiltersWithNullFiltersThrows() {
  1379. // Arrange
  1380. ControllerBase controller = new Mock<ControllerBase>().Object;
  1381. ControllerContext context = GetControllerContext(controller);
  1382. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  1383. // Act & Assert
  1384. ExceptionHelper.ExpectArgumentNullException(
  1385. delegate {
  1386. helper.PublicInvokeExceptionFilters(new Exception(), null /* filters */);
  1387. }, "filters");
  1388. }
  1389. [TestMethod]
  1390. public void InvokeResultFiltersOrdersFiltersCorrectly() {
  1391. // Arrange
  1392. List<string> actions = new List<string>();
  1393. ActionFilterImpl filter1 = new ActionFilterImpl() {
  1394. OnResultExecutingImpl = delegate(ResultExecutingContext filterContext) {
  1395. actions.Add("OnResultExecuting1");
  1396. },
  1397. OnResultExecutedImpl = delegate(ResultExecutedContext filterContext) {
  1398. actions.Add("OnResultExecuted1");
  1399. }
  1400. };
  1401. ActionFilterImpl filter2 = new ActionFilterImpl() {
  1402. OnResultExecutingImpl = delegate(ResultExecutingContext filterContext) {
  1403. actions.Add("OnResultExecuting2");
  1404. },
  1405. OnResultExecutedImpl = delegate(ResultExecutedContext filterContext) {
  1406. actions.Add("OnResultExecuted2");
  1407. }
  1408. };
  1409. Action continuation = delegate {
  1410. actions.Add("Continuation");
  1411. };
  1412. ActionResult actionResult = new ContinuationResult(continuation);
  1413. ControllerBase controller = new Mock<ControllerBase>().Object;
  1414. ControllerContext context = GetControllerContext(controller);
  1415. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  1416. // Act
  1417. helper.PublicInvokeActionResultWithFilters(actionResult, new List<IResultFilter>() { filter1, filter2 });
  1418. // Assert
  1419. Assert.AreEqual(5, actions.Count);
  1420. Assert.AreEqual("OnResultExecuting1", actions[0]);
  1421. Assert.AreEqual("OnResultExecuting2", actions[1]);
  1422. Assert.AreEqual("Continuation", actions[2]);
  1423. Assert.AreEqual("OnResultExecuted2", actions[3]);
  1424. Assert.AreEqual("OnResultExecuted1", actions[4]);
  1425. }
  1426. [TestMethod]
  1427. public void InvokeResultFiltersPassesArgumentsCorrectly() {
  1428. // Arrange
  1429. bool wasCalled = false;
  1430. Action continuation = delegate {
  1431. Assert.Fail("Continuation should not be called.");
  1432. };
  1433. ActionResult actionResult = new ContinuationResult(continuation);
  1434. ControllerBase controller = new Mock<ControllerBase>().Object;
  1435. ControllerContext context = GetControllerContext(controller);
  1436. ControllerActionInvokerHelper helper = new ControllerActionInvokerHelper(context);
  1437. ActionFilterImpl filter = new ActionFilterImpl() {
  1438. OnResultExecutingImpl = delegate(ResultExecutingContext filterContext) {
  1439. Assert.AreSame(actionResult, filterContext.Result);
  1440. Assert.IsFalse(wasCalled);
  1441. wasCalled = true;
  1442. filterContext.Cancel = true;
  1443. }
  1444. };
  1445. // Act
  1446. ResultExecutedContext result = helper.PublicInvokeActionResultWithFilters(actionResult,
  1447. new List<IResultFilter>() { filter });
  1448. // Assert
  1449. Assert.IsTrue(wasCalled);
  1450. Assert.IsNull(result.Exception);
  1451. Assert.IsFalse(result.ExceptionHandled);
  1452. Assert.AreSame(actionResult, result.Result);
  1453. }
  1454. [TestMethod]
  1455. public void InvokeResultFilterWhereContinuationThrowsExceptionAndIsHandled() {
  1456. // Arrange
  1457. List<string> actions = new List<string>();
  1458. ActionResult actionResult = new EmptyResult();
  1459. Exception exception = new Exception();
  1460. ActionFilterImpl filter = new ActionFilterImpl() {
  1461. OnResultExecutingImpl = delegate(ResultExecutingContext filterContext) {
  1462. actions.Add("OnResultExecuting");
  1463. },
  1464. OnResultExecutedImpl = delegate(ResultExecutedContext filterContext) {
  1465. actions.Add("OnResultExecuted");
  1466. Assert.AreSame(actionResult, filterContext.Result);
  1467. Assert.AreSame(exception, filterContext.Exception);
  1468. Assert.IsFalse(filterContext.ExceptionHandled);
  1469. filterContext.ExceptionHandled = true;
  1470. }
  1471. };
  1472. Func<ResultExecutedContext> continuation = delegate {
  1473. actions.Add("Continuation");
  1474. throw exception;
  1475. };
  1476. // Act
  1477. ResultExecutedContext result = ControllerActionInvoker.InvokeActionResultFilter(filter, new ResultExecutingContext(ControllerContextTest.GetControllerContext(), actionResult), continuation);
  1478. // Assert
  1479. Assert.AreEqual(3, actions.Count);
  1480. Assert.AreEqual("OnResultExecuting", actions[0]);
  1481. Assert.AreEqual("Continuation", actions[1]);
  1482. Assert.AreEqual("OnResultExecuted", actions[2]);
  1483. Assert.AreSame(exception, result.Exception);
  1484. Assert.IsTrue(result.ExceptionHandled);
  1485. Assert.AreSame(actionResult, result.Result);
  1486. }
  1487. [TestMethod]
  1488. public void InvokeResultFilterWhereContinuationThrowsExceptionAndIsNotHandled() {
  1489. // Arrange
  1490. List<string> actions = new List<string>();
  1491. ActionResult actionResult = new EmptyResult();
  1492. ActionFilterImpl filter = new ActionFilterImpl() {
  1493. OnResultExecutingImpl = delegate(ResultExecutingContext filterContext) {
  1494. actions.Add("OnResultExecuting");
  1495. },
  1496. OnResultExecutedImpl = delegate(ResultExecutedContext filterContext) {
  1497. actions.Add("OnResultExecuted");
  1498. }
  1499. };
  1500. Func<ResultExecutedContext> continuation = delegate {
  1501. actions.Add("Continuation");
  1502. throw new Exception("Some exception message.");
  1503. };
  1504. // Act & Assert
  1505. ExceptionHelper.ExpectException<Exception>(
  1506. delegate {
  1507. ControllerActionInvoker.InvokeActionResultFilter(filter, new ResultExecutingContext(ControllerContextTest.GetControllerContext(), actionResult), continuation);
  1508. },
  1509. "Some exception message.");
  1510. Assert.AreEqual(3, actions.Count);
  1511. Assert.AreEqual("OnResultExecuting", actions[0]);
  1512. Assert.AreEqual("Continuation", actions[1]);
  1513. Assert.AreEqual("OnResultExecuted", actions[2]);
  1514. }
  1515. [TestMethod]
  1516. public void InvokeResultFilterWhereContinuationThrowsThreadAbortException() {
  1517. // Arrange
  1518. List<string> actions = new List<string>();
  1519. ActionResult actionResult = new EmptyResult();
  1520. ActionFilterImpl filter = new ActionFilterImpl() {
  1521. OnResultExecutingImpl = delegate(ResultExecutingContext filterContext) {
  1522. actions.Add("OnResultExecuting");
  1523. },
  1524. OnResultExecutedImpl = delegate(ResultExecutedContext filterContext) {
  1525. Thread.ResetAbort();
  1526. actions.Add("OnResultExecuted");
  1527. Assert.AreSame(actionResult, filterContext.Result);
  1528. Assert.IsNull(filterContext.Exception);
  1529. Assert.IsFalse(filterContext.ExceptionHandled);
  1530. }
  1531. };
  1532. Func<ResultExecutedContext> continuation = delegate {
  1533. actions.Add("Continuation");
  1534. Thread.CurrentThread.Abort();
  1535. return null;
  1536. };
  1537. // Act & Assert
  1538. ExceptionHelper.ExpectException<ThreadAbortException>(
  1539. delegate {
  1540. ControllerActionInvoker.InvokeActionResultFilter(filter, new ResultExecutingContext(ControllerContextTest.GetControllerContext(), actionResult), continuation);
  1541. },
  1542. "Thread was being aborted.");
  1543. Assert.AreEqual(3, actions.Count);
  1544. Assert.AreEqual("OnResultExecuting", actions[0]);
  1545. Assert.AreEqual("Continuation", actions[1]);
  1546. Assert.AreEqual("OnResultExecuted", actions[2]);
  1547. }
  1548. [TestMethod]
  1549. public void InvokeResultFilterWhereOnResultExecutingCancels() {
  1550. // Arrange
  1551. bool wasCalled = false;
  1552. MethodInfo mi = typeof(object).GetMethod("ToString");
  1553. object[] paramValues = new object[0];
  1554. ActionResult actionResult = new EmptyResult();
  1555. ActionFilterImpl filter = new ActionFilterImpl() {
  1556. OnResultExecutingImpl = delegate(ResultExecutingContext filterContext) {
  1557. Assert.IsFalse(wasCalled);
  1558. wasCalled = true;
  1559. filterContext.Cancel = true;
  1560. },
  1561. };
  1562. Func<ResultExecutedContext> continuation = delegate {
  1563. Assert.Fail("The continuation should not be called.");
  1564. return null;
  1565. };
  1566. // Act
  1567. ResultExecutedContext result = ControllerActionInvoker.InvokeActionResultFilter(filter, new ResultExecutingContext(ControllerContextTest.GetControllerContext(), actionResult), continuation);
  1568. // Assert
  1569. Assert.IsTrue(wasCalled);
  1570. Assert.IsNull(result.Exception);
  1571. Assert.IsTrue(result.Canceled);
  1572. Assert.AreSame(actionResult, result.Result);
  1573. }
  1574. [TestMethod]
  1575. public void InvokeResultFilterWithNormalControlFlow() {
  1576. // Arrange
  1577. List<string> actions = new List<string>();
  1578. ActionResult actionResult = new EmptyResult();
  1579. ResultExecutedContext postContext = new ResultExecutedContext(ControllerContextTest.GetControllerContext(), actionResult, false /* canceled */, null /* exception */);
  1580. ActionFilterImpl filter = new ActionFilterImpl() {
  1581. OnResultExecutingImpl = delegate(ResultExecutingContext filterContext) {
  1582. Assert.AreSame(actionResult, filterContext.Result);
  1583. Assert.IsFalse(filterContext.Cancel);
  1584. actions.Add("OnResultExecuting");
  1585. },
  1586. OnResultExecutedImpl = delegate(ResultExecutedContext filterContext) {
  1587. Assert.AreEqual(postContext, filterContext);
  1588. actions.Add("OnResultExecuted");
  1589. }
  1590. };
  1591. Func<ResultExecutedContext> continuation = delegate {
  1592. actions.Add("Continuation");
  1593. return postContext;
  1594. };
  1595. // Act
  1596. ResultExecutedContext result = ControllerActionInvoker.InvokeActionResultFilter(filter, new ResultExecutingContext(ControllerContextTest.GetControllerContext(), actionResult), continuation);
  1597. // Assert
  1598. Assert.AreEqual(3, actions.Count);
  1599. Assert.AreEqual("OnResultExecuting", actions[0]);
  1600. Assert.AreEqual("Continuation", actions[1]);
  1601. Assert.AreEqual("OnResultExecuted", actions[2]);
  1602. Assert.AreSame(result, postContext);
  1603. }
  1604. [TestMethod]
  1605. public void CreateActionResultWithActionResultParameterReturnsParameterUnchanged() {
  1606. // Arrange
  1607. ControllerActionInvokerHelper invoker = new ControllerActionInvokerHelper();
  1608. ActionResult originalResult = new JsonResult();
  1609. // Act
  1610. ActionResult returnedActionResult = invoker.PublicCreateActionResult(originalResult);
  1611. // Assert
  1612. Assert.AreSame(originalResult, returnedActionResult);
  1613. }
  1614. [TestMethod]
  1615. public void CreateActionResultWithNullParameterReturnsEmptyResult() {
  1616. // Arrange
  1617. ControllerActionInvokerHelper invoker = new ControllerActionInvokerHelper();
  1618. // Act
  1619. ActionResult returnedActionResult = invoker.PublicCreateActionResult(null);
  1620. // Assert
  1621. Assert.IsInstanceOfType(returnedActionResult, typeof(EmptyResult));
  1622. }
  1623. [TestMethod]
  1624. public void CreateActionResultWithObjectParameterReturnsContentResult() {
  1625. // Arrange
  1626. ControllerActionInvokerHelper invoker = new ControllerActionInvokerHelper();
  1627. object originalReturnValue = new CultureReflector();
  1628. // Act
  1629. ActionResult returnedActionResult = invoker.PublicCreateActionResult(originalReturnValue);
  1630. // Assert
  1631. Assert.IsInstanceOfType(returnedActionResult, typeof(ContentResult));
  1632. ContentResult contentResult = (ContentResult)returnedActionResult;
  1633. Assert.AreEqual("IVL", contentResult.Content);
  1634. }
  1635. [TestMethod]
  1636. public void InvokeMethodCallsOverriddenCreateActionResult() {
  1637. // Arrange
  1638. CustomResultInvokerController controller = new CustomResultInvokerController();
  1639. ControllerContext context = GetControllerContext(controller);
  1640. CustomResultInvoker helper = new CustomResultInvoker(context);
  1641. MethodInfo mi = typeof(CustomResultInvokerController).GetMethod("ReturnCustomResult");
  1642. IDictionary<string, object> parameters = new Dictionary<string, object>();
  1643. // Act
  1644. ActionResult actionResult = helper.PublicInvokeActionMethod(mi, parameters);
  1645. // Assert (arg got passed to method + back correctly)
  1646. Assert.IsInstanceOfType(actionResult, typeof(CustomResult));
  1647. CustomResult customResult = (CustomResult)actionResult;
  1648. Assert.AreEqual("abc123", customResult.ReturnValue);
  1649. }
  1650. private static ControllerContext GetControllerContext(ControllerBase controller) {
  1651. return GetControllerContext(controller, null);
  1652. }
  1653. private static ControllerContext GetControllerContext(ControllerBase controller, IDictionary<string, object> values) {
  1654. RouteData routeData = new RouteData();
  1655. if (values != null) {
  1656. foreach (var entry in values) {
  1657. routeData.Values[entry.Key] = entry.Value;
  1658. }
  1659. }
  1660. Mock<HttpContextBase> contextMock = new Mock<HttpContextBase>();
  1661. contextMock.Expect(o => o.Request).Returns((HttpRequestBase)null); // make the TempDataDictionary happy
  1662. contextMock.Expect(o => o.Session).Returns((HttpSessionStateBase)null);
  1663. return new ControllerContext(contextMock.Object, routeData, controller);
  1664. }
  1665. private class EmptyActionFilterAttribute : ActionFilterAttribute {
  1666. }
  1667. private abstract class KeyedFilterAttribute : FilterAttribute {
  1668. public string Key {
  1669. get;
  1670. set;
  1671. }
  1672. }
  1673. private class KeyedAuthorizationFilterAttribute : KeyedFilterAttribute, IAuthorizationFilter {
  1674. public void OnAuthorization(AuthorizationContext filterContext) {
  1675. throw new NotImplementedException();
  1676. }
  1677. }
  1678. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
  1679. private class KeyedActionFilterAttribute : KeyedFilterAttribute, IActionFilter, IResultFilter {
  1680. public void OnActionExecuting(ActionExecutingContext filterContext) {
  1681. throw new NotImplementedException();
  1682. }
  1683. public void OnActionExecuted(ActionExecutedContext filterContext) {
  1684. throw new NotImplementedException();
  1685. }
  1686. public void OnResultExecuting(ResultExecutingContext filterContext) {
  1687. throw new NotImplementedException();
  1688. }
  1689. public void OnResultExecuted(ResultExecutedContext filterContext) {
  1690. throw new NotImplementedException();
  1691. }
  1692. }
  1693. private class ActionFilterImpl : IActionFilter, IResultFilter {
  1694. public Action<ActionExecutingContext> OnActionExecutingImpl {
  1695. get;
  1696. set;
  1697. }
  1698. public void OnActionExecuting(ActionExecutingContext filterContext) {
  1699. OnActionExecutingImpl(filterContext);
  1700. }
  1701. public Action<ActionExecutedContext> OnActionExecutedImpl {
  1702. get;
  1703. set;
  1704. }
  1705. public void OnActionExecuted(ActionExecutedContext filterContext) {
  1706. OnActionExecutedImpl(filterContext);
  1707. }
  1708. public Action<ResultExecutingContext> OnResultExecutingImpl {
  1709. get;
  1710. set;
  1711. }
  1712. public void OnResultExecuting(ResultExecutingContext filterContext) {
  1713. OnResultExecutingImpl(filterContext);
  1714. }
  1715. public Action<ResultExecutedContext> OnResultExecutedImpl {
  1716. get;
  1717. set;
  1718. }
  1719. public void OnResultExecuted(ResultExecutedContext filterContext) {
  1720. OnResultExecutedImpl(filterContext);
  1721. }
  1722. }
  1723. [KeyedActionFilter(Key = "BaseClass", Order = 0)]
  1724. [KeyedAuthorizationFilter(Key = "BaseClass", Order = 0)]
  1725. private class GetMemberChainController : Controller {
  1726. [KeyedActionFilter(Key = "BaseMethod", Order = 0)]
  1727. [KeyedAuthorizationFilter(Key = "BaseMethod", Order = 0)]
  1728. public virtual void SomeVirtual() {
  1729. }
  1730. }
  1731. [KeyedActionFilter(Key = "DerivedClass", Order = 1)]
  1732. private class GetMemberChainDerivedController : GetMemberChainController {
  1733. }
  1734. [KeyedActionFilter(Key = "SubderivedClass", Order = 2)]
  1735. private class GetMemberChainSubderivedController : GetMemberChainDerivedController {
  1736. [KeyedActionFilter(Key = "SubderivedMethod", Order = 2)]
  1737. public override void SomeVirtual() {
  1738. }
  1739. }
  1740. // This controller serves only to test vanilla method invocation - nothing exciting here
  1741. private class BasicMethodInvokeController : Controller {
  1742. public ActionResult ReturnsRenderView(object viewItem) {
  1743. return View("ReturnsRenderView", viewItem);
  1744. }
  1745. }
  1746. private class BlankController : Controller {
  1747. }
  1748. private sealed class CustomResult : ActionResult {
  1749. public object ReturnValue {
  1750. get;
  1751. set;
  1752. }
  1753. public override void ExecuteResult(ControllerContext context) {
  1754. throw new NotImplementedException();
  1755. }
  1756. }
  1757. private sealed class CustomResultInvokerController : Controller {
  1758. public object ReturnCustomResult() {
  1759. return "abc123";
  1760. }
  1761. }
  1762. private sealed class CustomResultInvoker : ControllerActionInvokerHelper {
  1763. public CustomResultInvoker(ControllerContext controllerContext)
  1764. : base(controllerContext) {
  1765. }
  1766. protected override ActionResult CreateActionResult(object actionReturnValue) {
  1767. return new CustomResult {
  1768. ReturnValue = actionReturnValue
  1769. };
  1770. }
  1771. }
  1772. private class ContinuationController : Controller {
  1773. private Func<ActionResult> _continuation;
  1774. public ContinuationController(Func<ActionResult> continuation) {
  1775. _continuation = continuation;
  1776. }
  1777. public ActionResult Go() {
  1778. return _continuation();
  1779. }
  1780. public static MethodInfo GoMethod {
  1781. get {
  1782. return typeof(ContinuationController).GetMethod("Go");
  1783. }
  1784. }
  1785. }
  1786. private class ContinuationResult : ActionResult {
  1787. private Action _continuation;
  1788. public ContinuationResult(Action continuation) {
  1789. _continuation = continuation;
  1790. }
  1791. public override void ExecuteResult(ControllerContext context) {
  1792. _continuation();
  1793. }
  1794. }
  1795. // This controller serves to test the default action method matching mechanism
  1796. private class FindMethodController : Controller {
  1797. public ActionResult ValidActionMethod() {
  1798. return null;
  1799. }
  1800. [NonAction]
  1801. public virtual ActionResult NonActionMethod() {
  1802. return null;
  1803. }
  1804. [NonAction]
  1805. public ActionResult DerivedIsActionMethod() {
  1806. return null;
  1807. }
  1808. public ActionResult MethodOverloaded() {
  1809. return null;
  1810. }
  1811. public ActionResult MethodOverloaded(string s) {
  1812. return null;
  1813. }
  1814. public void WrongReturnType() {
  1815. }
  1816. protected ActionResult ProtectedMethod() {
  1817. return null;
  1818. }
  1819. private ActionResult PrivateMethod() {
  1820. return null;
  1821. }
  1822. internal ActionResult InternalMethod() {
  1823. return null;
  1824. }
  1825. public override string ToString() {
  1826. // originally defined on Object
  1827. return base.ToString();
  1828. }
  1829. public ActionResult Property {
  1830. get {
  1831. return null;
  1832. }
  1833. }
  1834. #pragma warning disable 0067
  1835. // CS0067: Event declared but never used. We use reflection to access this member.
  1836. public event EventHandler Event;
  1837. #pragma warning restore 0067
  1838. }
  1839. private class DerivedFindMethodController : FindMethodController {
  1840. public override ActionResult NonActionMethod() {
  1841. return base.NonActionMethod();
  1842. }
  1843. // FindActionMethod() should accept this as a valid method since [NonAction] doesn't appear
  1844. // in its inheritance chain.
  1845. public new ActionResult DerivedIsActionMethod() {
  1846. return base.DerivedIsActionMethod();
  1847. }
  1848. }
  1849. // Similar to FindMethodController, but tests generics support specifically
  1850. private class GenericFindMethodController<T> : Controller {
  1851. public ActionResult ClosedGenericMethod(T t) {
  1852. return null;
  1853. }
  1854. public ActionResult OpenGenericMethod<U>(U t) {
  1855. return null;
  1856. }
  1857. }
  1858. // Allows for testing parameter conversions, etc.
  1859. private class ParameterTestingController : Controller {
  1860. public ParameterTestingController() {
  1861. Values = new Dictionary<string, object>();
  1862. }
  1863. public IDictionary<string, object> Values {
  1864. get;
  1865. private set;
  1866. }
  1867. public void Foo(string foo, string bar, string baz) {
  1868. Values["foo"] = foo;
  1869. Values["bar"] = bar;
  1870. Values["baz"] = baz;
  1871. }
  1872. public void HasOutParam(out string foo) {
  1873. foo = null;
  1874. }
  1875. public void HasRefParam(ref string foo) {
  1876. }
  1877. public void Parameterless() {
  1878. }
  1879. public void TakesInt(int id) {
  1880. Values["id"] = id;
  1881. }
  1882. public ActionResult TakesNullableInt(int? id) {
  1883. Values["id"] = id;
  1884. return null;
  1885. }
  1886. public void TakesString(string id) {
  1887. }
  1888. public void TakesDateTime(DateTime id) {
  1889. }
  1890. }
  1891. // Provides access to the protected members of ControllerActionInvoker
  1892. public class ControllerActionInvokerHelper : ControllerActionInvoker {
  1893. public ControllerActionInvokerHelper() {
  1894. // set instance caches to prevent modifying global test application state
  1895. DispatcherCache = new ActionMethodDispatcherCache();
  1896. SelectorCache = new ActionMethodSelectorCache();
  1897. }
  1898. public ControllerActionInvokerHelper(ControllerContext controllerContext)
  1899. : this() {
  1900. ControllerContext = controllerContext;
  1901. }
  1902. protected override MethodInfo FindActionMethod(string actionName) {
  1903. return PublicFindActionMethod(actionName);
  1904. }
  1905. public virtual MethodInfo PublicFindActionMethod(string actionName) {
  1906. return base.FindActionMethod(actionName);
  1907. }
  1908. protected override FilterInfo GetFiltersForActionMethod(MethodInfo methodInfo) {
  1909. return PublicGetFiltersForActionMethod(methodInfo);
  1910. }
  1911. public virtual FilterInfo PublicGetFiltersForActionMethod(MethodInfo methodInfo) {
  1912. return base.GetFiltersForActionMethod(methodInfo);
  1913. }
  1914. protected override object GetParameterValue(ParameterInfo parameterInfo) {
  1915. return PublicGetParameterValue(parameterInfo);
  1916. }
  1917. public virtual object PublicGetParameterValue(ParameterInfo parameterInfo) {
  1918. return base.GetParameterValue(parameterInfo);
  1919. }
  1920. protected override IDictionary<string, object> GetParameterValues(MethodInfo methodInfo) {
  1921. return PublicGetParameterValues(methodInfo);
  1922. }
  1923. public virtual IDictionary<string, object> PublicGetParameterValues(MethodInfo methodInfo) {
  1924. return base.GetParameterValues(methodInfo);
  1925. }
  1926. protected override ActionResult InvokeActionMethod(MethodInfo methodInfo, IDictionary<string, object> parameters) {
  1927. return PublicInvokeActionMethod(methodInfo, parameters);
  1928. }
  1929. public virtual ActionResult PublicInvokeActionMethod(MethodInfo methodInfo, IDictionary<string, object> parameters) {
  1930. return base.InvokeActionMethod(methodInfo, parameters);
  1931. }
  1932. protected override ActionExecutedContext InvokeActionMethodWithFilters(MethodInfo methodInfo, IDictionary<string, object> parameters, IList<IActionFilter> filters) {
  1933. return PublicInvokeActionMethodWithFilters(methodInfo, parameters, filters);
  1934. }
  1935. public virtual ActionExecutedContext PublicInvokeActionMethodWithFilters(MethodInfo methodInfo, IDictionary<string, object> parameters, IList<IActionFilter> filters) {
  1936. return base.InvokeActionMethodWithFilters(methodInfo, parameters, filters);
  1937. }
  1938. protected override void InvokeActionResult(ActionResult actionResult) {
  1939. PublicInvokeActionResult(actionResult);
  1940. }
  1941. public virtual void PublicInvokeActionResult(ActionResult actionResult) {
  1942. base.InvokeActionResult(actionResult);
  1943. }
  1944. protected override ResultExecutedContext InvokeActionResultWithFilters(ActionResult actionResult, IList<IResultFilter> filters) {
  1945. return PublicInvokeActionResultWithFilters(actionResult, filters);
  1946. }
  1947. public virtual ResultExecutedContext PublicInvokeActionResultWithFilters(ActionResult actionResult, IList<IResultFilter> filters) {
  1948. return base.InvokeActionResultWithFilters(actionResult, filters);
  1949. }
  1950. protected override AuthorizationContext InvokeAuthorizationFilters(MethodInfo methodInfo, IList<IAuthorizationFilter> filters) {
  1951. return PublicInvokeAuthorizationFilters(methodInfo, filters);
  1952. }
  1953. public virtual AuthorizationContext PublicInvokeAuthorizationFilters(MethodInfo methodInfo, IList<IAuthorizationFilter> filters) {
  1954. return base.InvokeAuthorizationFilters(methodInfo, filters);
  1955. }
  1956. protected override ExceptionContext InvokeExceptionFilters(Exception exception, IList<IExceptionFilter> filters) {
  1957. return PublicInvokeExceptionFilters(exception, filters);
  1958. }
  1959. public virtual ExceptionContext PublicInvokeExceptionFilters(Exception exception, IList<IExceptionFilter> filters) {
  1960. return base.InvokeExceptionFilters(exception, filters);
  1961. }
  1962. public ActionResult PublicCreateActionResult(object result) {
  1963. return CreateActionResult(result);
  1964. }
  1965. public struct FilterInfoHelper {
  1966. public IList<IActionFilter> ActionFilters;
  1967. public IList<IAuthorizationFilter> AuthorizationFilters;
  1968. public IList<IExceptionFilter> ExceptionFilters;
  1969. public IList<IResultFilter> ResultFilters;
  1970. }
  1971. }
  1972. public class AuthorizationFilterHelper : IAuthorizationFilter {
  1973. private IList<AuthorizationFilterHelper> _callQueue;
  1974. public bool ShouldCancel;
  1975. public ActionResult ShortCircuitResult;
  1976. public AuthorizationFilterHelper(IList<AuthorizationFilterHelper> callQueue) {
  1977. _callQueue = callQueue;
  1978. }
  1979. public void OnAuthorization(AuthorizationContext filterContext) {
  1980. _callQueue.Add(this);
  1981. if (ShouldCancel) {
  1982. filterContext.Cancel = true;
  1983. filterContext.Result = ShortCircuitResult;
  1984. }
  1985. }
  1986. }
  1987. public class ExceptionFilterHelper : IExceptionFilter {
  1988. private IList<ExceptionFilterHelper> _callQueue;
  1989. public bool ShouldHandleException;
  1990. public ExceptionContext ContextPassed;
  1991. public ExceptionFilterHelper(IList<ExceptionFilterHelper> callQueue) {
  1992. _callQueue = callQueue;
  1993. }
  1994. public void OnException(ExceptionContext filterContext) {
  1995. _callQueue.Add(this);
  1996. if (ShouldHandleException) {
  1997. filterContext.ExceptionHandled = true;
  1998. }
  1999. ContextPassed = filterContext;
  2000. }
  2001. }
  2002. private class CustomConverterController : Controller {
  2003. public void ParameterWithoutBindAttribute([PredicateReflector] string someParam) {
  2004. }
  2005. public void ParameterHasBindAttribute([Bind(Include = "foo"), PredicateReflector] string someParam) {
  2006. }
  2007. public void ParameterHasFieldPrefix([Bind(Prefix = "bar")] string foo) {
  2008. }
  2009. public void ParameterHasNullFieldPrefix([Bind(Include = "whatever")] string foo) {
  2010. }
  2011. public void ParameterHasEmptyFieldPrefix([Bind(Prefix = "")] MySimpleModel foo) {
  2012. }
  2013. public void ParameterHasNoConverters(string foo) {
  2014. }
  2015. public void ParameterHasOneConverter([MyCustomConverter] string foo) {
  2016. }
  2017. public void ParameterHasTwoConverters([MyCustomConverter, MyCustomConverter] string foo) {
  2018. }
  2019. }
  2020. public class MySimpleModel {
  2021. public int IntProp { get; set; }
  2022. public string StringProp { get; set; }
  2023. }
  2024. [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = false)]
  2025. private class PredicateReflectorAttribute : CustomModelBinderAttribute {
  2026. public override IModelBinder GetBinder() {
  2027. return new MyConverter();
  2028. }
  2029. private class MyConverter : IModelBinder {
  2030. public ModelBinderResult BindModel(ModelBindingContext bindingContext) {
  2031. string s = String.Format("foo={0}&bar={1}", bindingContext.ShouldUpdateProperty("foo"), bindingContext.ShouldUpdateProperty("bar"));
  2032. return new ModelBinderResult(s);
  2033. }
  2034. }
  2035. }
  2036. [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true, Inherited = false)]
  2037. private class MyCustomConverterAttribute : CustomModelBinderAttribute {
  2038. public override IModelBinder GetBinder() {
  2039. return new MyConverter();
  2040. }
  2041. private class MyConverter : IModelBinder {
  2042. public ModelBinderResult BindModel(ModelBindingContext bindingContext) {
  2043. string s = bindingContext.ModelName + "_" + bindingContext.ModelType.Name;
  2044. return new ModelBinderResult(s);
  2045. }
  2046. }
  2047. }
  2048. }
  2049. }