PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/test/System.Web.Mvc.Test/Async/Test/AsyncControllerActionInvokerTest.cs

https://bitbucket.org/mdavid/aspnetwebstack
C# | 916 lines | 695 code | 151 blank | 70 comment | 9 complexity | a4afccd917a1cb9fac8d42cb8e65b8f3 MD5 | raw file
  1. using System.Collections.Generic;
  2. using System.Threading;
  3. using Moq;
  4. using Xunit;
  5. using Assert = Microsoft.TestCommon.AssertEx;
  6. namespace System.Web.Mvc.Async.Test
  7. {
  8. public class AsyncControllerActionInvokerTest
  9. {
  10. [Fact]
  11. public void InvokeAction_ActionNotFound()
  12. {
  13. // Arrange
  14. ControllerContext controllerContext = GetControllerContext();
  15. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  16. // Act
  17. IAsyncResult asyncResult = invoker.BeginInvokeAction(controllerContext, "ActionNotFound", null, null);
  18. bool retVal = invoker.EndInvokeAction(asyncResult);
  19. // Assert
  20. Assert.False(retVal);
  21. }
  22. [Fact]
  23. public void InvokeAction_ActionThrowsException_Handled()
  24. {
  25. // Arrange
  26. ControllerContext controllerContext = GetControllerContext();
  27. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  28. // Act & assert
  29. IAsyncResult asyncResult = invoker.BeginInvokeAction(controllerContext, "ActionThrowsExceptionAndIsHandled", null, null);
  30. Assert.Null(((TestController)controllerContext.Controller).Log); // Result filter shouldn't have executed yet
  31. bool retVal = invoker.EndInvokeAction(asyncResult);
  32. Assert.True(retVal);
  33. Assert.Equal("From exception filter", ((TestController)controllerContext.Controller).Log);
  34. }
  35. [Fact]
  36. public void InvokeAction_ActionThrowsException_NotHandled()
  37. {
  38. // Arrange
  39. ControllerContext controllerContext = GetControllerContext();
  40. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  41. // Act & assert
  42. Assert.Throws<Exception>(
  43. delegate { invoker.BeginInvokeAction(controllerContext, "ActionThrowsExceptionAndIsNotHandled", null, null); },
  44. @"Some exception text.");
  45. }
  46. [Fact]
  47. public void InvokeAction_ActionThrowsException_ThreadAbort()
  48. {
  49. // Arrange
  50. ControllerContext controllerContext = GetControllerContext();
  51. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  52. // Act & assert
  53. Assert.Throws<ThreadAbortException>(
  54. delegate { invoker.BeginInvokeAction(controllerContext, "ActionCallsThreadAbort", null, null); });
  55. }
  56. [Fact]
  57. public void InvokeAction_AuthorizationFilterShortCircuits()
  58. {
  59. // Arrange
  60. ControllerContext controllerContext = GetControllerContext();
  61. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  62. // Act
  63. IAsyncResult asyncResult = invoker.BeginInvokeAction(controllerContext, "AuthorizationFilterShortCircuits", null, null);
  64. bool retVal = invoker.EndInvokeAction(asyncResult);
  65. // Assert
  66. Assert.True(retVal);
  67. Assert.Equal("From authorization filter", ((TestController)controllerContext.Controller).Log);
  68. }
  69. [Fact]
  70. public void InvokeAction_NormalAction()
  71. {
  72. // Arrange
  73. ControllerContext controllerContext = GetControllerContext();
  74. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  75. // Act
  76. IAsyncResult asyncResult = invoker.BeginInvokeAction(controllerContext, "NormalAction", null, null);
  77. bool retVal = invoker.EndInvokeAction(asyncResult);
  78. // Assert
  79. Assert.True(retVal);
  80. Assert.Equal("From action", ((TestController)controllerContext.Controller).Log);
  81. }
  82. [Fact]
  83. public void InvokeAction_OverrideFindAction()
  84. {
  85. // Arrange
  86. ControllerContext controllerContext = GetControllerContext();
  87. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvokerWithCustomFindAction();
  88. // Act
  89. IAsyncResult asyncResult = invoker.BeginInvokeAction(controllerContext, actionName: "Non-ExistantAction", callback: null, state: null);
  90. bool retVal = invoker.EndInvokeAction(asyncResult);
  91. // Assert
  92. Assert.True(retVal);
  93. Assert.Equal("From action", ((TestController)controllerContext.Controller).Log);
  94. }
  95. [Fact]
  96. public void InvokeAction_RequestValidationFails()
  97. {
  98. // Arrange
  99. ControllerContext controllerContext = GetControllerContext(passesRequestValidation: false);
  100. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  101. // Act & assert
  102. Assert.Throws<HttpRequestValidationException>(
  103. delegate { invoker.BeginInvokeAction(controllerContext, "NormalAction", null, null); });
  104. }
  105. [Fact]
  106. public void InvokeAction_ResultThrowsException_Handled()
  107. {
  108. // Arrange
  109. ControllerContext controllerContext = GetControllerContext();
  110. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  111. // Act & assert
  112. IAsyncResult asyncResult = invoker.BeginInvokeAction(controllerContext, "ResultThrowsExceptionAndIsHandled", null, null);
  113. bool retVal = invoker.EndInvokeAction(asyncResult);
  114. Assert.True(retVal);
  115. Assert.Equal("From exception filter", ((TestController)controllerContext.Controller).Log);
  116. }
  117. [Fact]
  118. public void InvokeAction_ResultThrowsException_NotHandled()
  119. {
  120. // Arrange
  121. ControllerContext controllerContext = GetControllerContext();
  122. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  123. // Act & assert
  124. IAsyncResult asyncResult = invoker.BeginInvokeAction(controllerContext, "ResultThrowsExceptionAndIsNotHandled", null, null);
  125. Assert.Throws<Exception>(
  126. delegate { invoker.EndInvokeAction(asyncResult); },
  127. @"Some exception text.");
  128. }
  129. [Fact]
  130. public void InvokeAction_ResultThrowsException_ThreadAbort()
  131. {
  132. // Arrange
  133. ControllerContext controllerContext = GetControllerContext();
  134. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  135. // Act & assert
  136. IAsyncResult asyncResult = invoker.BeginInvokeAction(controllerContext, "ResultCallsThreadAbort", null, null);
  137. Assert.Throws<ThreadAbortException>(
  138. delegate { invoker.EndInvokeAction(asyncResult); });
  139. }
  140. [Fact]
  141. public void InvokeAction_ThrowsIfActionNameIsEmpty()
  142. {
  143. // Arrange
  144. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  145. // Act & assert
  146. Assert.ThrowsArgumentNullOrEmpty(
  147. delegate { invoker.BeginInvokeAction(new ControllerContext(), "", null, null); }, "actionName");
  148. }
  149. [Fact]
  150. public void InvokeAction_ThrowsIfActionNameIsNull()
  151. {
  152. // Arrange
  153. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  154. // Act & assert
  155. Assert.ThrowsArgumentNullOrEmpty(
  156. delegate { invoker.BeginInvokeAction(new ControllerContext(), null, null, null); }, "actionName");
  157. }
  158. [Fact]
  159. public void InvokeAction_ThrowsIfControllerContextIsNull()
  160. {
  161. // Arrange
  162. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  163. // Act & assert
  164. Assert.ThrowsArgumentNull(
  165. delegate { invoker.BeginInvokeAction(null, "someAction", null, null); }, "controllerContext");
  166. }
  167. [Fact]
  168. public void InvokeActionMethod_AsynchronousDescriptor()
  169. {
  170. // Arrange
  171. ControllerContext controllerContext = new ControllerContext();
  172. Dictionary<string, object> parameters = new Dictionary<string, object>();
  173. IAsyncResult innerAsyncResult = new MockAsyncResult();
  174. ActionResult expectedResult = new ViewResult();
  175. Mock<AsyncActionDescriptor> mockActionDescriptor = new Mock<AsyncActionDescriptor>();
  176. mockActionDescriptor.Setup(d => d.BeginExecute(controllerContext, parameters, It.IsAny<AsyncCallback>(), It.IsAny<object>())).Returns(innerAsyncResult);
  177. mockActionDescriptor.Setup(d => d.EndExecute(innerAsyncResult)).Returns(expectedResult);
  178. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  179. // Act
  180. IAsyncResult asyncResult = invoker.BeginInvokeActionMethod(controllerContext, mockActionDescriptor.Object, parameters, null, null);
  181. ActionResult returnedResult = invoker.EndInvokeActionMethod(asyncResult);
  182. // Assert
  183. Assert.Equal(expectedResult, returnedResult);
  184. }
  185. [Fact]
  186. public void InvokeActionMethod_SynchronousDescriptor()
  187. {
  188. // Arrange
  189. ControllerContext controllerContext = new ControllerContext();
  190. Dictionary<string, object> parameters = new Dictionary<string, object>();
  191. ActionResult expectedResult = new ViewResult();
  192. Mock<ActionDescriptor> mockActionDescriptor = new Mock<ActionDescriptor>();
  193. mockActionDescriptor.Setup(d => d.Execute(controllerContext, parameters)).Returns(expectedResult);
  194. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  195. // Act
  196. IAsyncResult asyncResult = invoker.BeginInvokeActionMethod(controllerContext, mockActionDescriptor.Object, parameters, null, null);
  197. ActionResult returnedResult = invoker.EndInvokeActionMethod(asyncResult);
  198. // Assert
  199. Assert.Equal(expectedResult, returnedResult);
  200. }
  201. [Fact]
  202. public void InvokeActionMethodFilterAsynchronously_NextInChainThrowsOnActionExecutedException_Handled()
  203. {
  204. // Arrange
  205. ViewResult expectedResult = new ViewResult();
  206. bool nextInChainWasCalled = false;
  207. bool onActionExecutedWasCalled = false;
  208. ActionExecutingContext preContext = GetActionExecutingContext();
  209. ActionFilterImpl actionFilter = new ActionFilterImpl()
  210. {
  211. OnActionExecutedImpl = filterContext =>
  212. {
  213. onActionExecutedWasCalled = true;
  214. Assert.NotNull(filterContext.Exception);
  215. filterContext.ExceptionHandled = true;
  216. filterContext.Result = expectedResult;
  217. }
  218. };
  219. // Act & assert pre-execution
  220. Func<ActionExecutedContext> continuation = AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(
  221. actionFilter, preContext,
  222. () => () =>
  223. {
  224. nextInChainWasCalled = true;
  225. throw new Exception("Some exception text.");
  226. });
  227. Assert.False(onActionExecutedWasCalled);
  228. // Act & assert post-execution
  229. ActionExecutedContext postContext = continuation();
  230. Assert.True(nextInChainWasCalled);
  231. Assert.True(onActionExecutedWasCalled);
  232. Assert.Equal(expectedResult, postContext.Result);
  233. }
  234. [Fact]
  235. public void InvokeActionMethodFilterAsynchronously_NextInChainThrowsOnActionExecutedException_NotHandled()
  236. {
  237. // Arrange
  238. ViewResult expectedResult = new ViewResult();
  239. bool onActionExecutedWasCalled = false;
  240. ActionExecutingContext preContext = GetActionExecutingContext();
  241. ActionFilterImpl actionFilter = new ActionFilterImpl()
  242. {
  243. OnActionExecutedImpl = filterContext => { onActionExecutedWasCalled = true; }
  244. };
  245. // Act & assert
  246. Func<ActionExecutedContext> continuation = AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(actionFilter, preContext,
  247. () => () => { throw new Exception("Some exception text."); });
  248. Assert.Throws<Exception>(
  249. delegate { continuation(); },
  250. @"Some exception text.");
  251. // Assert
  252. Assert.True(onActionExecutedWasCalled);
  253. }
  254. [Fact]
  255. public void InvokeActionMethodFilterAsynchronously_NextInChainThrowsOnActionExecutedException_ThreadAbort()
  256. {
  257. // Arrange
  258. ViewResult expectedResult = new ViewResult();
  259. bool onActionExecutedWasCalled = false;
  260. ActionExecutingContext preContext = GetActionExecutingContext();
  261. ActionFilterImpl actionFilter = new ActionFilterImpl()
  262. {
  263. OnActionExecutedImpl = filterContext =>
  264. {
  265. onActionExecutedWasCalled = true;
  266. Thread.ResetAbort();
  267. }
  268. };
  269. // Act & assert
  270. Func<ActionExecutedContext> continuation = AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(
  271. actionFilter, preContext,
  272. () => () =>
  273. {
  274. Thread.CurrentThread.Abort();
  275. return null;
  276. });
  277. Assert.Throws<ThreadAbortException>(
  278. delegate { continuation(); });
  279. // Assert
  280. Assert.True(onActionExecutedWasCalled);
  281. }
  282. [Fact]
  283. public void InvokeActionMethodFilterAsynchronously_NextInChainThrowsOnActionExecutingException_Handled()
  284. {
  285. // Arrange
  286. ViewResult expectedResult = new ViewResult();
  287. bool nextInChainWasCalled = false;
  288. bool onActionExecutingWasCalled = false;
  289. bool onActionExecutedWasCalled = false;
  290. ActionExecutingContext preContext = GetActionExecutingContext();
  291. ActionFilterImpl actionFilter = new ActionFilterImpl()
  292. {
  293. OnActionExecutingImpl = filterContext => { onActionExecutingWasCalled = true; },
  294. OnActionExecutedImpl = filterContext =>
  295. {
  296. onActionExecutedWasCalled = true;
  297. Assert.NotNull(filterContext.Exception);
  298. filterContext.ExceptionHandled = true;
  299. filterContext.Result = expectedResult;
  300. }
  301. };
  302. // Act
  303. Func<ActionExecutedContext> continuation = AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(
  304. actionFilter, preContext,
  305. () =>
  306. {
  307. nextInChainWasCalled = true;
  308. throw new Exception("Some exception text.");
  309. });
  310. // Assert
  311. Assert.True(nextInChainWasCalled);
  312. Assert.True(onActionExecutingWasCalled);
  313. Assert.True(onActionExecutedWasCalled);
  314. ActionExecutedContext postContext = continuation();
  315. Assert.Equal(expectedResult, postContext.Result);
  316. }
  317. [Fact]
  318. public void InvokeActionMethodFilterAsynchronously_NextInChainThrowsOnActionExecutingException_NotHandled()
  319. {
  320. // Arrange
  321. ViewResult expectedResult = new ViewResult();
  322. bool nextInChainWasCalled = false;
  323. bool onActionExecutingWasCalled = false;
  324. bool onActionExecutedWasCalled = false;
  325. ActionExecutingContext preContext = GetActionExecutingContext();
  326. ActionFilterImpl actionFilter = new ActionFilterImpl()
  327. {
  328. OnActionExecutingImpl = filterContext => { onActionExecutingWasCalled = true; },
  329. OnActionExecutedImpl = filterContext => { onActionExecutedWasCalled = true; }
  330. };
  331. // Act & assert
  332. Assert.Throws<Exception>(
  333. delegate
  334. {
  335. AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(
  336. actionFilter, preContext,
  337. () =>
  338. {
  339. nextInChainWasCalled = true;
  340. throw new Exception("Some exception text.");
  341. });
  342. },
  343. @"Some exception text.");
  344. // Assert
  345. Assert.True(nextInChainWasCalled);
  346. Assert.True(onActionExecutingWasCalled);
  347. Assert.True(onActionExecutedWasCalled);
  348. }
  349. [Fact]
  350. public void InvokeActionMethodFilterAsynchronously_NextInChainThrowsOnActionExecutingException_ThreadAbort()
  351. {
  352. // Arrange
  353. ViewResult expectedResult = new ViewResult();
  354. bool nextInChainWasCalled = false;
  355. bool onActionExecutingWasCalled = false;
  356. bool onActionExecutedWasCalled = false;
  357. ActionExecutingContext preContext = GetActionExecutingContext();
  358. ActionFilterImpl actionFilter = new ActionFilterImpl()
  359. {
  360. OnActionExecutingImpl = filterContext => { onActionExecutingWasCalled = true; },
  361. OnActionExecutedImpl = filterContext =>
  362. {
  363. onActionExecutedWasCalled = true;
  364. Thread.ResetAbort();
  365. }
  366. };
  367. // Act & assert
  368. Assert.Throws<ThreadAbortException>(
  369. delegate
  370. {
  371. AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(
  372. actionFilter, preContext,
  373. () =>
  374. {
  375. nextInChainWasCalled = true;
  376. Thread.CurrentThread.Abort();
  377. return null;
  378. });
  379. });
  380. // Assert
  381. Assert.True(nextInChainWasCalled);
  382. Assert.True(onActionExecutingWasCalled);
  383. Assert.True(onActionExecutedWasCalled);
  384. }
  385. [Fact]
  386. public void InvokeActionMethodFilterAsynchronously_NormalExecutionNotCanceled()
  387. {
  388. // Arrange
  389. bool nextInChainWasCalled = false;
  390. bool onActionExecutingWasCalled = false;
  391. bool onActionExecutedWasCalled = false;
  392. ActionExecutingContext preContext = GetActionExecutingContext();
  393. ActionFilterImpl actionFilter = new ActionFilterImpl()
  394. {
  395. OnActionExecutingImpl = _ => { onActionExecutingWasCalled = true; },
  396. OnActionExecutedImpl = _ => { onActionExecutedWasCalled = true; }
  397. };
  398. // Act
  399. Func<ActionExecutedContext> continuation = AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(
  400. actionFilter, preContext,
  401. () =>
  402. {
  403. nextInChainWasCalled = true;
  404. return () => new ActionExecutedContext();
  405. });
  406. // Assert
  407. Assert.True(nextInChainWasCalled);
  408. Assert.True(onActionExecutingWasCalled);
  409. Assert.False(onActionExecutedWasCalled);
  410. continuation();
  411. Assert.True(onActionExecutedWasCalled);
  412. }
  413. [Fact]
  414. public void InvokeActionMethodFilterAsynchronously_OnActionExecutingSetsResult()
  415. {
  416. // Arrange
  417. ViewResult expectedResult = new ViewResult();
  418. bool nextInChainWasCalled = false;
  419. bool onActionExecutingWasCalled = false;
  420. bool onActionExecutedWasCalled = false;
  421. ActionExecutingContext preContext = GetActionExecutingContext();
  422. ActionFilterImpl actionFilter = new ActionFilterImpl()
  423. {
  424. OnActionExecutingImpl = filterContext =>
  425. {
  426. onActionExecutingWasCalled = true;
  427. filterContext.Result = expectedResult;
  428. },
  429. OnActionExecutedImpl = _ => { onActionExecutedWasCalled = true; }
  430. };
  431. // Act
  432. Func<ActionExecutedContext> continuation = AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(
  433. actionFilter, preContext,
  434. () =>
  435. {
  436. nextInChainWasCalled = true;
  437. return () => new ActionExecutedContext();
  438. });
  439. // Assert
  440. Assert.False(nextInChainWasCalled);
  441. Assert.True(onActionExecutingWasCalled);
  442. Assert.False(onActionExecutedWasCalled);
  443. ActionExecutedContext postContext = continuation();
  444. Assert.False(onActionExecutedWasCalled);
  445. Assert.Equal(expectedResult, postContext.Result);
  446. }
  447. [Fact]
  448. public void InvokeActionMethodWithFilters()
  449. {
  450. // Arrange
  451. List<string> actionLog = new List<string>();
  452. ControllerContext controllerContext = new ControllerContext();
  453. Dictionary<string, object> parameters = new Dictionary<string, object>();
  454. MockAsyncResult innerAsyncResult = new MockAsyncResult();
  455. ActionResult actionResult = new ViewResult();
  456. ActionFilterImpl filter1 = new ActionFilterImpl()
  457. {
  458. OnActionExecutingImpl = delegate(ActionExecutingContext filterContext) { actionLog.Add("OnActionExecuting1"); },
  459. OnActionExecutedImpl = delegate(ActionExecutedContext filterContext) { actionLog.Add("OnActionExecuted1"); }
  460. };
  461. ActionFilterImpl filter2 = new ActionFilterImpl()
  462. {
  463. OnActionExecutingImpl = delegate(ActionExecutingContext filterContext) { actionLog.Add("OnActionExecuting2"); },
  464. OnActionExecutedImpl = delegate(ActionExecutedContext filterContext) { actionLog.Add("OnActionExecuted2"); }
  465. };
  466. Mock<AsyncActionDescriptor> mockActionDescriptor = new Mock<AsyncActionDescriptor>();
  467. mockActionDescriptor.Setup(d => d.BeginExecute(controllerContext, parameters, It.IsAny<AsyncCallback>(), It.IsAny<object>())).Returns(innerAsyncResult);
  468. mockActionDescriptor.Setup(d => d.EndExecute(innerAsyncResult)).Returns(actionResult);
  469. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  470. IActionFilter[] filters = new IActionFilter[] { filter1, filter2 };
  471. // Act
  472. IAsyncResult outerAsyncResult = invoker.BeginInvokeActionMethodWithFilters(controllerContext, filters, mockActionDescriptor.Object, parameters, null, null);
  473. ActionExecutedContext postContext = invoker.EndInvokeActionMethodWithFilters(outerAsyncResult);
  474. // Assert
  475. Assert.Equal(new[] { "OnActionExecuting1", "OnActionExecuting2", "OnActionExecuted2", "OnActionExecuted1" }, actionLog.ToArray());
  476. Assert.Equal(actionResult, postContext.Result);
  477. }
  478. [Fact]
  479. public void InvokeActionMethodWithFilters_ShortCircuited()
  480. {
  481. // Arrange
  482. List<string> actionLog = new List<string>();
  483. ControllerContext controllerContext = new ControllerContext();
  484. Dictionary<string, object> parameters = new Dictionary<string, object>();
  485. ActionResult actionResult = new ViewResult();
  486. ActionFilterImpl filter1 = new ActionFilterImpl()
  487. {
  488. OnActionExecutingImpl = delegate(ActionExecutingContext filterContext) { actionLog.Add("OnActionExecuting1"); },
  489. OnActionExecutedImpl = delegate(ActionExecutedContext filterContext) { actionLog.Add("OnActionExecuted1"); }
  490. };
  491. ActionFilterImpl filter2 = new ActionFilterImpl()
  492. {
  493. OnActionExecutingImpl = delegate(ActionExecutingContext filterContext)
  494. {
  495. actionLog.Add("OnActionExecuting2");
  496. filterContext.Result = actionResult;
  497. },
  498. OnActionExecutedImpl = delegate(ActionExecutedContext filterContext) { actionLog.Add("OnActionExecuted2"); }
  499. };
  500. Mock<AsyncActionDescriptor> mockActionDescriptor = new Mock<AsyncActionDescriptor>();
  501. mockActionDescriptor.Setup(d => d.BeginExecute(controllerContext, parameters, It.IsAny<AsyncCallback>(), It.IsAny<object>())).Throws(new Exception("I shouldn't have been called."));
  502. mockActionDescriptor.Setup(d => d.EndExecute(It.IsAny<IAsyncResult>())).Throws(new Exception("I shouldn't have been called."));
  503. AsyncControllerActionInvoker invoker = new AsyncControllerActionInvoker();
  504. IActionFilter[] filters = new IActionFilter[] { filter1, filter2 };
  505. // Act
  506. IAsyncResult outerAsyncResult = invoker.BeginInvokeActionMethodWithFilters(controllerContext, filters, mockActionDescriptor.Object, parameters, null, null);
  507. ActionExecutedContext postContext = invoker.EndInvokeActionMethodWithFilters(outerAsyncResult);
  508. // Assert
  509. Assert.Equal(new[] { "OnActionExecuting1", "OnActionExecuting2", "OnActionExecuted1" }, actionLog.ToArray());
  510. Assert.Equal(actionResult, postContext.Result);
  511. }
  512. private static ActionExecutingContext GetActionExecutingContext()
  513. {
  514. return new ActionExecutingContext(new ControllerContext(), new Mock<ActionDescriptor>().Object, new Dictionary<string, object>());
  515. }
  516. private static ControllerContext GetControllerContext(bool passesRequestValidation = true)
  517. {
  518. Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
  519. if (passesRequestValidation)
  520. {
  521. #pragma warning disable 618
  522. mockHttpContext.Setup(o => o.Request.ValidateInput()).AtMostOnce();
  523. #pragma warning restore 618
  524. }
  525. else
  526. {
  527. mockHttpContext.Setup(o => o.Request.ValidateInput()).Throws(new HttpRequestValidationException());
  528. }
  529. return new ControllerContext()
  530. {
  531. Controller = new TestController(),
  532. HttpContext = mockHttpContext.Object
  533. };
  534. }
  535. private class ActionFilterImpl : IActionFilter, IResultFilter
  536. {
  537. public Action<ActionExecutingContext> OnActionExecutingImpl { get; set; }
  538. public void OnActionExecuting(ActionExecutingContext filterContext)
  539. {
  540. if (OnActionExecutingImpl != null)
  541. {
  542. OnActionExecutingImpl(filterContext);
  543. }
  544. }
  545. public Action<ActionExecutedContext> OnActionExecutedImpl { get; set; }
  546. public void OnActionExecuted(ActionExecutedContext filterContext)
  547. {
  548. if (OnActionExecutedImpl != null)
  549. {
  550. OnActionExecutedImpl(filterContext);
  551. }
  552. }
  553. public Action<ResultExecutingContext> OnResultExecutingImpl { get; set; }
  554. public void OnResultExecuting(ResultExecutingContext filterContext)
  555. {
  556. if (OnResultExecutingImpl != null)
  557. {
  558. OnResultExecutingImpl(filterContext);
  559. }
  560. }
  561. public Action<ResultExecutedContext> OnResultExecutedImpl { get; set; }
  562. public void OnResultExecuted(ResultExecutedContext filterContext)
  563. {
  564. if (OnResultExecutedImpl != null)
  565. {
  566. OnResultExecutedImpl(filterContext);
  567. }
  568. }
  569. }
  570. public class AsyncControllerActionInvokerHelper : AsyncControllerActionInvoker
  571. {
  572. public AsyncControllerActionInvokerHelper()
  573. {
  574. DescriptorCache = new ControllerDescriptorCache();
  575. }
  576. protected override ControllerDescriptor GetControllerDescriptor(ControllerContext controllerContext)
  577. {
  578. return PublicGetControllerDescriptor(controllerContext);
  579. }
  580. public virtual ControllerDescriptor PublicGetControllerDescriptor(ControllerContext controllerContext)
  581. {
  582. return base.GetControllerDescriptor(controllerContext);
  583. }
  584. protected override ExceptionContext InvokeExceptionFilters(ControllerContext controllerContext, IList<IExceptionFilter> filters, Exception exception)
  585. {
  586. return PublicInvokeExceptionFilters(controllerContext, filters, exception);
  587. }
  588. public virtual ExceptionContext PublicInvokeExceptionFilters(ControllerContext controllerContext, IList<IExceptionFilter> filters, Exception exception)
  589. {
  590. return base.InvokeExceptionFilters(controllerContext, filters, exception);
  591. }
  592. protected override void InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
  593. {
  594. PublicInvokeActionResult(controllerContext, actionResult);
  595. }
  596. public virtual void PublicInvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
  597. {
  598. base.InvokeActionResult(controllerContext, actionResult);
  599. }
  600. protected override FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
  601. {
  602. return PublicGetFilters(controllerContext, actionDescriptor);
  603. }
  604. public virtual FilterInfo PublicGetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
  605. {
  606. return base.GetFilters(controllerContext, actionDescriptor);
  607. }
  608. protected override AuthorizationContext InvokeAuthorizationFilters(ControllerContext controllerContext, IList<IAuthorizationFilter> filters, ActionDescriptor actionDescriptor)
  609. {
  610. return PublicInvokeAuthorizationFilters(controllerContext, filters, actionDescriptor);
  611. }
  612. public virtual AuthorizationContext PublicInvokeAuthorizationFilters(ControllerContext controllerContext, IList<IAuthorizationFilter> filters, ActionDescriptor actionDescriptor)
  613. {
  614. return base.InvokeAuthorizationFilters(controllerContext, filters, actionDescriptor);
  615. }
  616. protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
  617. {
  618. return PublicFindAction(controllerContext, controllerDescriptor, actionName);
  619. }
  620. public virtual ActionDescriptor PublicFindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
  621. {
  622. return base.FindAction(controllerContext, controllerDescriptor, actionName);
  623. }
  624. protected override IDictionary<string, object> GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
  625. {
  626. return PublicGetParameterValues(controllerContext, actionDescriptor);
  627. }
  628. public virtual IDictionary<string, object> PublicGetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
  629. {
  630. return base.GetParameterValues(controllerContext, actionDescriptor);
  631. }
  632. }
  633. public class AsyncControllerActionInvokerWithCustomFindAction : AsyncControllerActionInvoker
  634. {
  635. protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
  636. {
  637. return base.FindAction(controllerContext, controllerDescriptor, "NormalAction");
  638. }
  639. }
  640. [ResetThreadAbort]
  641. private class TestController : AsyncController
  642. {
  643. public string Log;
  644. public ActionResult ActionCallsThreadAbortAsync()
  645. {
  646. Thread.CurrentThread.Abort();
  647. return null;
  648. }
  649. public ActionResult ActionCallsThreadAbortCompleted()
  650. {
  651. return null;
  652. }
  653. public ActionResult ResultCallsThreadAbort()
  654. {
  655. return new ActionResultWhichCallsThreadAbort();
  656. }
  657. public ActionResult NormalAction()
  658. {
  659. return new LoggingActionResult("From action");
  660. }
  661. [AuthorizationFilterReturnsResult]
  662. public void AuthorizationFilterShortCircuits()
  663. {
  664. }
  665. [CustomExceptionFilterHandlesError]
  666. public void ActionThrowsExceptionAndIsHandledAsync()
  667. {
  668. throw new Exception("Some exception text.");
  669. }
  670. public void ActionThrowsExceptionAndIsHandledCompleted()
  671. {
  672. }
  673. [CustomExceptionFilterDoesNotHandleError]
  674. public void ActionThrowsExceptionAndIsNotHandledAsync()
  675. {
  676. throw new Exception("Some exception text.");
  677. }
  678. public void ActionThrowsExceptionAndIsNotHandledCompleted()
  679. {
  680. }
  681. [CustomExceptionFilterHandlesError]
  682. public ActionResult ResultThrowsExceptionAndIsHandled()
  683. {
  684. return new ActionResultWhichThrowsException();
  685. }
  686. [CustomExceptionFilterDoesNotHandleError]
  687. public ActionResult ResultThrowsExceptionAndIsNotHandled()
  688. {
  689. return new ActionResultWhichThrowsException();
  690. }
  691. private class AuthorizationFilterReturnsResultAttribute : FilterAttribute, IAuthorizationFilter
  692. {
  693. public void OnAuthorization(AuthorizationContext filterContext)
  694. {
  695. filterContext.Result = new LoggingActionResult("From authorization filter");
  696. }
  697. }
  698. private class CustomExceptionFilterDoesNotHandleErrorAttribute : FilterAttribute, IExceptionFilter
  699. {
  700. public void OnException(ExceptionContext filterContext)
  701. {
  702. }
  703. }
  704. private class CustomExceptionFilterHandlesErrorAttribute : FilterAttribute, IExceptionFilter
  705. {
  706. public void OnException(ExceptionContext filterContext)
  707. {
  708. filterContext.ExceptionHandled = true;
  709. filterContext.Result = new LoggingActionResult("From exception filter");
  710. }
  711. }
  712. private class ActionResultWhichCallsThreadAbort : ActionResult
  713. {
  714. public override void ExecuteResult(ControllerContext context)
  715. {
  716. Thread.CurrentThread.Abort();
  717. }
  718. }
  719. private class ActionResultWhichThrowsException : ActionResult
  720. {
  721. public override void ExecuteResult(ControllerContext context)
  722. {
  723. throw new Exception("Some exception text.");
  724. }
  725. }
  726. }
  727. private class ResetThreadAbortAttribute : ActionFilterAttribute
  728. {
  729. public override void OnActionExecuted(ActionExecutedContext filterContext)
  730. {
  731. try
  732. {
  733. Thread.ResetAbort();
  734. }
  735. catch (ThreadStateException)
  736. {
  737. // thread wasn't being aborted
  738. }
  739. }
  740. public override void OnResultExecuted(ResultExecutedContext filterContext)
  741. {
  742. try
  743. {
  744. Thread.ResetAbort();
  745. }
  746. catch (ThreadStateException)
  747. {
  748. // thread wasn't being aborted
  749. }
  750. }
  751. }
  752. private class LoggingActionResult : ActionResult
  753. {
  754. private readonly string _logText;
  755. public LoggingActionResult(string logText)
  756. {
  757. _logText = logText;
  758. }
  759. public override void ExecuteResult(ControllerContext context)
  760. {
  761. ((TestController)context.Controller).Log = _logText;
  762. }
  763. }
  764. }
  765. }