Skip to content

Commit dea3a25

Browse files
committed
Async execution of ModuleActionItemsAttribute ActionFilterAttribute.
1 parent 6adcc6b commit dea3a25

5 files changed

Lines changed: 86 additions & 46 deletions

File tree

DNN Platform/DotNetNuke.Web.Mvc/Framework/ActionFilters/ModuleActionItemsAttribute.cs

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,47 @@ public class ModuleActionItemsAttribute : ActionFilterAttribute
2626
public override void OnActionExecuting(ActionExecutingContext filterContext)
2727
{
2828
var controller = filterContext.Controller as IDnnController;
29+
var result = this.InvokeMethod(filterContext, controller, false);
30+
if (result is ModuleActionCollection moduleActions)
31+
{
32+
controller.ModuleActions = moduleActions;
33+
}
34+
}
35+
36+
public async Task OnActionExecutingAsync(ActionExecutingContext filterContext)
37+
{
38+
var controller = filterContext.Controller as IDnnController;
39+
var result = this.InvokeMethod(filterContext, controller, true);
40+
if (result is ModuleActionCollection moduleActions)
41+
{
42+
controller.ModuleActions = moduleActions;
43+
}
44+
else if (result is Task<ModuleActionCollection> taskResult)
45+
{
46+
controller.ModuleActions = await taskResult;
47+
}
48+
}
49+
50+
private static MethodInfo GetMethod(Type type, string methodName, bool supportsAsync)
51+
{
52+
var method = type.GetMethod(methodName);
53+
54+
if (method == null)
55+
{
56+
throw new NotImplementedException($"The expected method to get the module actions cannot be found. Type: {type.FullName}, Method: {methodName}");
57+
}
58+
59+
var returnType = method.ReturnType;
60+
if (returnType == typeof(ModuleActionCollection) || (supportsAsync && returnType == typeof(Task<ModuleActionCollection>)))
61+
{
62+
return method;
63+
}
64+
65+
throw new InvalidOperationException("The method must return an object of type ModuleActionCollection");
66+
}
67+
68+
private object InvokeMethod(ActionExecutingContext filterContext, IDnnController controller, bool supportsAsync)
69+
{
2970
Type type;
3071
string methodName;
3172

@@ -56,35 +97,9 @@ public override void OnActionExecuting(ActionExecutingContext filterContext)
5697
methodName = this.MethodName;
5798
}
5899

59-
var method = GetMethod(type, methodName, controller.IsAsync);
60-
61-
var result = method.Invoke(instance, null);
62-
if (result is ModuleActionCollection moduleActions)
63-
{
64-
controller.ModuleActions = moduleActions;
65-
}
66-
else if (result is Task<ModuleActionCollection> taskResult)
67-
{
68-
controller.ModuleActionsAsync = taskResult;
69-
}
70-
}
71-
72-
private static MethodInfo GetMethod(Type type, string methodName, bool supportsAsync)
73-
{
74-
var method = type.GetMethod(methodName);
75-
76-
if (method == null)
77-
{
78-
throw new NotImplementedException($"The expected method to get the module actions cannot be found. Type: {type.FullName}, Method: {methodName}");
79-
}
80-
81-
var returnType = method.ReturnType;
82-
if (returnType == typeof(ModuleActionCollection) || (supportsAsync && returnType == typeof(Task<ModuleActionCollection>)))
83-
{
84-
return method;
85-
}
100+
var method = GetMethod(type, methodName, supportsAsync);
86101

87-
throw new InvalidOperationException("The method must return an object of type ModuleActionCollection");
102+
return method.Invoke(instance, null);
88103
}
89104
}
90105
}

DNN Platform/DotNetNuke.Web.Mvc/Framework/Controllers/DnnController.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,6 @@ public ActionResult ResultOfLastExecute
7373
/// <inheritdoc />
7474
public ModuleActionCollection ModuleActions { get; set; }
7575

76-
/// <inheritdoc/>
77-
public Task<ModuleActionCollection> ModuleActionsAsync { get; set; }
78-
79-
/// <inheritdoc/>
80-
public bool IsAsync { get; set; }
81-
8276
/// <inheritdoc />
8377
public ModuleInstanceContext ModuleContext { get; set; }
8478

DNN Platform/DotNetNuke.Web.Mvc/Framework/Controllers/IDnnController.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
namespace DotNetNuke.Web.Mvc.Framework.Controllers
66
{
77
using System.Diagnostics.CodeAnalysis;
8-
using System.Threading.Tasks;
98
using System.Web.Mvc;
109
using System.Web.UI;
1110

@@ -25,10 +24,6 @@ public interface IDnnController : IController
2524

2625
ModuleActionCollection ModuleActions { get; set; }
2726

28-
Task<ModuleActionCollection> ModuleActionsAsync { get; set; }
29-
30-
bool IsAsync { get; set; }
31-
3227
ModuleInstanceContext ModuleContext { get; set; }
3328

3429
bool ValidateRequest { get; set; }

DNN Platform/DotNetNuke.Web.Mvc/Framework/Modules/ModuleApplication.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ namespace DotNetNuke.Web.Mvc.Framework.Modules
66
using System;
77
using System.Globalization;
88
using System.Reflection;
9-
using System.Runtime.Remoting.Contexts;
109
using System.Threading;
1110
using System.Threading.Tasks;
1211
using System.Web;
@@ -176,8 +175,6 @@ public virtual async Task<ModuleRequestResult> ExecuteRequestAsync(ModuleRequest
176175
throw new InvalidOperationException("Could Not Construct Controller");
177176
}
178177

179-
moduleController.IsAsync = true;
180-
181178
moduleController.ValidateRequest = false;
182179

183180
moduleController.DnnPage = context.DnnPage;
@@ -199,10 +196,6 @@ public virtual async Task<ModuleRequestResult> ExecuteRequestAsync(ModuleRequest
199196
// if our ActionFilter is executed after the ActionResult has triggered an Exception the filter
200197
// MUST explicitly flip the ExceptionHandled bit otherwise the view will not render
201198
await Task.Factory.FromAsync(asyncController.BeginExecute, asyncController.EndExecute, this.RequestContext, null);
202-
if (moduleController.ModuleActionsAsync != null)
203-
{
204-
moduleController.ModuleActions = await moduleController.ModuleActionsAsync;
205-
}
206199

207200
var result = moduleController.ResultOfLastExecute;
208201

DNN Platform/DotNetNuke.Web.Mvc/Framework/Modules/ResultCapturingActionInvoker.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,55 @@ namespace DotNetNuke.Web.Mvc.Framework.Modules
66
{
77
using System;
88
using System.Collections.Generic;
9+
using System.Linq;
10+
using System.Threading.Tasks;
911
using System.Web.Mvc;
1012
using System.Web.Mvc.Async;
1113

14+
using DotNetNuke.Web.Mvc.Framework.ActionFilters;
15+
1216
public class ResultCapturingActionInvoker : AsyncControllerActionInvoker
1317
{
1418
public ActionResult ResultOfLastInvoke { get; set; }
1519

20+
/// <inheritdoc />
21+
protected override IAsyncResult BeginInvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters, AsyncCallback callback, object state)
22+
{
23+
var moduleActionsFilter = filters.OfType<ModuleActionItemsAttribute>().ToList();
24+
if (moduleActionsFilter.Count == 0)
25+
{
26+
return base.BeginInvokeActionMethodWithFilters(controllerContext, filters, actionDescriptor, parameters, callback, state);
27+
}
28+
29+
var tcs = new TaskCompletionSource<bool>(state);
30+
var filterContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);
31+
var task = Task.CompletedTask;
32+
foreach (var filter in moduleActionsFilter)
33+
{
34+
task = task.ContinueWith(_ => filter.OnActionExecutingAsync(filterContext));
35+
}
36+
37+
task.ContinueWith(t =>
38+
{
39+
if (t.IsFaulted)
40+
{
41+
tcs.TrySetException(t.Exception.InnerExceptions);
42+
}
43+
else if (t.IsCanceled)
44+
{
45+
tcs.TrySetCanceled();
46+
}
47+
else
48+
{
49+
tcs.TrySetResult(true);
50+
}
51+
52+
IAsyncResult BeginDelegate(AsyncCallback innerCallback, object innerState) => base.BeginInvokeActionMethodWithFilters(controllerContext, [.. filters.Where(f => f is not ModuleActionItemsAttribute)], actionDescriptor, parameters, innerCallback, innerState);
53+
return Task.Factory.FromAsync(BeginDelegate, ar => callback(ar), state);
54+
});
55+
return tcs.Task;
56+
}
57+
1658
/// <inheritdoc />
1759
protected override ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
1860
{
@@ -21,6 +63,7 @@ protected override ActionExecutedContext InvokeActionMethodWithFilters(Controlle
2163
return context;
2264
}
2365

66+
/// <inheritdoc />
2467
protected override ActionExecutedContext EndInvokeActionMethodWithFilters(IAsyncResult asyncResult)
2568
{
2669
var context = base.EndInvokeActionMethodWithFilters(asyncResult);

0 commit comments

Comments
 (0)