Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions DNN Platform/DotNetNuke.Web.Mvc/AsyncMvcHostControl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information
namespace DotNetNuke.Web.Mvc
{
using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.UI;

using DotNetNuke.Services.Exceptions;
using DotNetNuke.UI.Modules;
using DotNetNuke.Web.Mvc.Routing;

public class AsyncMvcHostControl : MvcHostControl, IAsyncModuleControl
{
public AsyncMvcHostControl()
: base()
{
}

public AsyncMvcHostControl(string controlKey)
: base(controlKey)
{
}

protected override void OnInitInternal(EventArgs e)
{
if (this.ExecuteModuleImmediately)
{
this.Page.RegisterAsyncTask(new PageAsyncTask(this.ExecuteModuleAsync));
}
}

protected override void OnPreRenderInternal(EventArgs e)
{
// We need to defer execution to after the async task registered in OnInitInternal above, which will only get executed at the WebForms async point, just before PreRenderComplete.
this.Page.RegisterAsyncTask(new PageAsyncTask(this.OnPreRenderAsync));
}

protected async Task ExecuteModuleAsync(CancellationToken cancellationToken)
{
try
{
HttpContextBase httpContext = new HttpContextWrapper(HttpContext.Current);

var moduleExecutionEngine = GetModuleExecutionEngine();

this.Result = await moduleExecutionEngine.ExecuteModuleAsync(this.GetModuleRequestContext(httpContext), cancellationToken);

this.ModuleActions = this.LoadActions(this.Result);

httpContext.SetModuleRequestResult(this.Result);
}
catch (Exception exc)
{
Exceptions.ProcessModuleLoadException(this, exc);
}
}

private Task OnPreRenderAsync(CancellationToken cancellationToken)
{
try
{
if (this.Result == null)
{
return Task.CompletedTask;
}

var mvcString = RenderModule(this.Result);
if (!string.IsNullOrEmpty(Convert.ToString(mvcString, CultureInfo.InvariantCulture)))
{
this.Controls.Add(new LiteralControl(Convert.ToString(mvcString, CultureInfo.InvariantCulture)));
}
}
catch (Exception exc)
{
Exceptions.ProcessModuleLoadException(this, exc);
}

return Task.CompletedTask;
}
}
}
48 changes: 48 additions & 0 deletions DNN Platform/DotNetNuke.Web.Mvc/AsyncMvcSettingsControl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information

namespace DotNetNuke.Web.Mvc
{
using System;
using System.Threading;
using System.Threading.Tasks;

using DotNetNuke.Entities.Modules;
using DotNetNuke.UI.Modules;

public class AsyncMvcSettingsControl : AsyncMvcHostControl, IAsyncSettingsControl
{
public AsyncMvcSettingsControl()
: base("Settings")
{
this.ExecuteModuleImmediately = false;
}

/// <inheritdoc/>
public void LoadSettings()
{
throw new NotSupportedException("Async controls need to call LoadSettingsAsync.");
}

/// <inheritdoc/>
public Task LoadSettingsAsync(CancellationToken cancellationToken)
{
return this.ExecuteModuleAsync(cancellationToken);
}

/// <inheritdoc/>
public void UpdateSettings()
{
throw new NotSupportedException("Async controls need to call UpdateSettingsAsync.");
}

/// <inheritdoc/>
public async Task UpdateSettingsAsync(CancellationToken cancellationToken)
{
await this.ExecuteModuleAsync(cancellationToken);

ModuleController.Instance.UpdateModule(this.ModuleContext.Configuration);
}
}
}
26 changes: 9 additions & 17 deletions DNN Platform/DotNetNuke.Web.Mvc/DnnMvcHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
namespace DotNetNuke.Web.Mvc
{
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
Expand All @@ -26,7 +28,7 @@ namespace DotNetNuke.Web.Mvc

using Microsoft.Extensions.DependencyInjection;

public class DnnMvcHandler : IHttpHandler, IRequiresSessionState
public class DnnMvcHandler : HttpTaskAsyncHandler, IRequiresSessionState
{
public static readonly string MvcVersionHeaderName = "X-AspNetMvc-Version";

Expand All @@ -41,19 +43,13 @@ public DnnMvcHandler(RequestContext requestContext)

public RequestContext RequestContext { get; private set; }

/// <inheritdoc />
bool IHttpHandler.IsReusable => this.IsReusable;

internal ControllerBuilder ControllerBuilder
{
get => this.controllerBuilder ??= ControllerBuilder.Current;
set => this.controllerBuilder = value;
}

protected virtual bool IsReusable => false;

/// <inheritdoc />
void IHttpHandler.ProcessRequest(HttpContext httpContext)
public override async Task ProcessRequestAsync(HttpContext context)
{
SetThreadCulture();
MembershipModule.AuthenticateRequest(
Expand All @@ -65,18 +61,20 @@ void IHttpHandler.ProcessRequest(HttpContext httpContext)
Globals.GetCurrentServiceProvider().GetRequiredService<IHostSettings>(),
this.RequestContext.HttpContext,
allowUnknownExtensions: true);
this.ProcessRequest(httpContext);

var httpContextBase = new HttpContextWrapper(context);
await this.ProcessRequestAsync(httpContextBase, httpContextBase.Response.ClientDisconnectedToken);
}

protected internal virtual void ProcessRequest(HttpContextBase httpContext)
protected internal virtual async Task ProcessRequestAsync(HttpContextBase httpContext, CancellationToken cancellationToken)
{
try
{
var moduleExecutionEngine = GetModuleExecutionEngine();

// Check if the controller supports IDnnController
var moduleResult =
moduleExecutionEngine.ExecuteModule(this.GetModuleRequestContext(httpContext));
await moduleExecutionEngine.ExecuteModuleAsync(this.GetModuleRequestContext(httpContext), cancellationToken);
httpContext.SetModuleRequestResult(moduleResult);
this.RenderModule(moduleResult);
}
Expand All @@ -85,12 +83,6 @@ protected internal virtual void ProcessRequest(HttpContextBase httpContext)
}
}

protected virtual void ProcessRequest(HttpContext httpContext)
{
HttpContextBase httpContextBase = new HttpContextWrapper(httpContext);
this.ProcessRequest(httpContextBase);
}

private static void SetThreadCulture()
{
var portalSettings = PortalController.Instance.GetCurrentSettings();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace DotNetNuke.Web.Mvc.Framework.ActionFilters
using System;
using System.Globalization;
using System.Reflection;
using System.Threading.Tasks;
using System.Web.Mvc;

using DotNetNuke.Entities.Modules.Actions;
Expand All @@ -25,6 +26,47 @@ public class ModuleActionItemsAttribute : ActionFilterAttribute
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var controller = filterContext.Controller as IDnnController;
var result = this.InvokeMethod(filterContext, controller, false);
if (result is ModuleActionCollection moduleActions)
{
controller.ModuleActions = moduleActions;
}
}

public async Task OnActionExecutingAsync(ActionExecutingContext filterContext)
{
var controller = filterContext.Controller as IDnnController;
var result = this.InvokeMethod(filterContext, controller, true);
if (result is ModuleActionCollection moduleActions)
{
controller.ModuleActions = moduleActions;
}
else if (result is Task<ModuleActionCollection> taskResult)
{
controller.ModuleActions = await taskResult;
}
}

private static MethodInfo GetMethod(Type type, string methodName, bool supportsAsync)
{
var method = type.GetMethod(methodName);

if (method == null)
{
throw new NotImplementedException($"The expected method to get the module actions cannot be found. Type: {type.FullName}, Method: {methodName}");
}

var returnType = method.ReturnType;
if (returnType == typeof(ModuleActionCollection) || (supportsAsync && returnType == typeof(Task<ModuleActionCollection>)))
{
return method;
}

throw new InvalidOperationException("The method must return an object of type ModuleActionCollection");
}

private object InvokeMethod(ActionExecutingContext filterContext, IDnnController controller, bool supportsAsync)
{
Type type;
string methodName;

Expand Down Expand Up @@ -55,27 +97,9 @@ public override void OnActionExecuting(ActionExecutingContext filterContext)
methodName = this.MethodName;
}

var method = GetMethod(type, methodName);

controller.ModuleActions = method.Invoke(instance, null) as ModuleActionCollection;
}

private static MethodInfo GetMethod(Type type, string methodName)
{
var method = type.GetMethod(methodName);

if (method == null)
{
throw new NotImplementedException($"The expected method to get the module actions cannot be found. Type: {type.FullName}, Method: {methodName}");
}

var returnType = method.ReturnType.FullName;
if (returnType != "DotNetNuke.Entities.Modules.Actions.ModuleActionCollection")
{
throw new InvalidOperationException("The method must return an object of type ModuleActionCollection");
}
var method = GetMethod(type, methodName, supportsAsync);

return method;
return method.Invoke(instance, null);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public void ExecuteResult(ControllerContext context, TextWriter writer)

if (this.View == null)
{
result = this.ViewEngineCollection.FindPartialView(context, this.ViewName);
result = this.FindView(context);
Comment thread
mitchelsellers marked this conversation as resolved.
this.View = result.View;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public void ExecuteResult(ControllerContext context, TextWriter writer)

if (this.View == null)
{
result = this.ViewEngineCollection.FindView(context, this.ViewName, this.MasterName);
result = this.FindView(context);
this.View = result.View;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace DotNetNuke.Web.Mvc.Framework.Controllers
using System;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.UI;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
namespace DotNetNuke.Web.Mvc.Framework.Modules
{
using System.IO;
using System.Threading;
using System.Threading.Tasks;

public interface IModuleExecutionEngine
{
ModuleRequestResult ExecuteModule(ModuleRequestContext moduleRequestContext);

Task<ModuleRequestResult> ExecuteModuleAsync(ModuleRequestContext moduleRequestContext, CancellationToken cancellationToken);
Comment thread
bdukes marked this conversation as resolved.

void ExecuteModuleResult(ModuleRequestResult moduleResult, TextWriter writer);
}
}
Loading
Loading