From 84da613d2c03b6f1c0fa3c01828923ec3415d525 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Fri, 12 Apr 2019 00:08:58 +0100 Subject: [PATCH] Cache OnStarting callback delegate (#9283) --- .../src/Filters/SaveTempDataFilter.cs | 62 ++++++++++--------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/Mvc/Mvc.ViewFeatures/src/Filters/SaveTempDataFilter.cs b/src/Mvc/Mvc.ViewFeatures/src/Filters/SaveTempDataFilter.cs index 0ab2ec33a1..ff677f68f5 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/Filters/SaveTempDataFilter.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/Filters/SaveTempDataFilter.cs @@ -14,6 +14,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Filters /// internal class SaveTempDataFilter : IResourceFilter, IResultFilter { + private static readonly Func OnStartingCallback = (state) => OnStarting((HttpContext)state); // Internal for unit testing internal static readonly object SaveTempDataFilterContextKey = new object(); @@ -43,38 +44,39 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Filters if (!context.HttpContext.Response.HasStarted) { - context.HttpContext.Response.OnStarting((state) => - { - var httpContext = (HttpContext)state; - - var saveTempDataContext = GetTempDataContext(context.HttpContext); - if (saveTempDataContext.RequestHasUnhandledException) - { - return Task.CompletedTask; - } - - // If temp data was already saved, skip trying to save again as the calls here would potentially fail - // because the session feature might not be available at this point. - // Example: An action returns NoContentResult and since NoContentResult does not write anything to - // the body of the response, this delegate would get executed way late in the pipeline at which point - // the session feature would have been removed. - if (saveTempDataContext.TempDataSaved) - { - return Task.CompletedTask; - } - - SaveTempData( - result: null, - factory: saveTempDataContext.TempDataDictionaryFactory, - filters: saveTempDataContext.Filters, - httpContext: httpContext); - - return Task.CompletedTask; - }, - state: context.HttpContext); + context.HttpContext.Response.OnStarting( + callback: OnStartingCallback, + state: context.HttpContext); } } + private static Task OnStarting(HttpContext httpContext) + { + var saveTempDataContext = GetTempDataContext(httpContext); + if (saveTempDataContext.RequestHasUnhandledException) + { + return Task.CompletedTask; + } + + // If temp data was already saved, skip trying to save again as the calls here would potentially fail + // because the session feature might not be available at this point. + // Example: An action returns NoContentResult and since NoContentResult does not write anything to + // the body of the response, this delegate would get executed way late in the pipeline at which point + // the session feature would have been removed. + if (saveTempDataContext.TempDataSaved) + { + return Task.CompletedTask; + } + + SaveTempData( + result: null, + factory: saveTempDataContext.TempDataDictionaryFactory, + filters: saveTempDataContext.Filters, + httpContext: httpContext); + + return Task.CompletedTask; + } + /// public void OnResourceExecuted(ResourceExecutedContext context) { @@ -115,7 +117,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Filters } } - private SaveTempDataContext GetTempDataContext(HttpContext httpContext) + private static SaveTempDataContext GetTempDataContext(HttpContext httpContext) { SaveTempDataContext saveTempDataContext = null; if (httpContext.Items.TryGetValue(SaveTempDataFilterContextKey, out var value))