From 14ea3f25d5e604ca5ad3e86bb6b4a88f5cbecab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Standa=20Luke=C5=A1?= Date: Fri, 29 Sep 2023 10:27:12 +0200 Subject: [PATCH] Fix AspNetCore UseExceptionHandler applied on postbacks AspNetCore reexecutes the same request with the original POST method. If a DotVVM page is handling the error, we assumed that we need to execute a postback in the Error page. The request body was usually already consumed, and even if wasn't a matching command wasnt found. resolves #1700 --- .../Framework/Hosting/HostingConstants.cs | 1 + .../Hosting/Middlewares/DotvvmMiddleware.cs | 20 ++++++++++++------- .../EmptyWeb/Pages/Error/ErrorViewModel.cs | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/Framework/Framework/Hosting/HostingConstants.cs b/src/Framework/Framework/Hosting/HostingConstants.cs index d6c24d85e1..a25834d099 100644 --- a/src/Framework/Framework/Hosting/HostingConstants.cs +++ b/src/Framework/Framework/Hosting/HostingConstants.cs @@ -5,6 +5,7 @@ namespace DotVVM.Framework.Hosting public class HostingConstants { public const string DotvvmRequestContextKey = "dotvvm.requestContext"; + public const string DotvvmIsErrorHandlingKey = "dotvvm.isErrorHandling"; public const string GlobalizeCultureUrlPath = "dotvvmGlobalizeCulture"; public const string GlobalizeCultureUrlIdParameter = "id"; diff --git a/src/Framework/Hosting.AspNetCore/Hosting/Middlewares/DotvvmMiddleware.cs b/src/Framework/Hosting.AspNetCore/Hosting/Middlewares/DotvvmMiddleware.cs index 1838de6a1e..ff15065af8 100644 --- a/src/Framework/Hosting.AspNetCore/Hosting/Middlewares/DotvvmMiddleware.cs +++ b/src/Framework/Hosting.AspNetCore/Hosting/Middlewares/DotvvmMiddleware.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using DotVVM.Framework.Configuration; using DotVVM.Framework.Hosting.ErrorPages; using DotVVM.Framework.Hosting.Middlewares; using DotVVM.Framework.ResourceManagement; +using DotVVM.Framework.Utils; using DotVVM.Framework.ViewModel.Serialization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Localization; @@ -40,8 +42,13 @@ public DotvvmMiddleware(RequestDelegate next, DotvvmConfiguration configuration, /// public async Task Invoke(HttpContext context) { - // create the context - var dotvvmContext = CreateDotvvmContext(context); + // If we are handling an error, assume that the request is Navigate, otherwise we are attempting to execute postbacks from a different page + var assumedRequestType = +#if NET6_0_OR_GREATER + context.Features[typeof(Microsoft.AspNetCore.Diagnostics.IExceptionHandlerFeature)] is {} ? DotvvmRequestType.Navigate : +#endif + (DotvvmRequestType?)null; + var dotvvmContext = CreateDotvvmContext(context, assumedRequestType); context.RequestServices.GetRequiredService().Context = dotvvmContext; context.Items[HostingConstants.DotvvmRequestContextKey] = dotvvmContext; @@ -101,14 +108,13 @@ public static IHttpContext ConvertHttpContext(HttpContext context) return httpContext; } - protected DotvvmRequestContext CreateDotvvmContext(HttpContext context) - { - return new DotvvmRequestContext( + protected DotvvmRequestContext CreateDotvvmContext(HttpContext context, DotvvmRequestType? requestType = null) => + new DotvvmRequestContext( ConvertHttpContext(context), Configuration, - context.RequestServices + context.RequestServices, + requestType ); - } public static bool IsInCurrentVirtualDirectory(IHttpContext context, ref string url) { diff --git a/src/Templates/content/EmptyWeb/Pages/Error/ErrorViewModel.cs b/src/Templates/content/EmptyWeb/Pages/Error/ErrorViewModel.cs index fed88c7f92..e3a755c45c 100644 --- a/src/Templates/content/EmptyWeb/Pages/Error/ErrorViewModel.cs +++ b/src/Templates/content/EmptyWeb/Pages/Error/ErrorViewModel.cs @@ -34,7 +34,7 @@ public override Task Init() ExceptionType = "View called without IExceptionHandlerFeature"; return base.Init(); } - ExceptionType = exceptionInfo.Error.GetType().Name; + ExceptionType = exceptionInfo.Error.GetBaseException().GetType().Name; RequestId = aspcontext.TraceIdentifier; RequestPath = exceptionInfo.Path; return base.Init();