diff --git a/src/Mvc/Mvc.Core/src/ChallengeResult.cs b/src/Mvc/Mvc.Core/src/ChallengeResult.cs
index 95cb90ed279f..2fc451faa188 100644
--- a/src/Mvc/Mvc.Core/src/ChallengeResult.cs
+++ b/src/Mvc/Mvc.Core/src/ChallengeResult.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Linq;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc;
///
/// An that on execution invokes .
///
-public class ChallengeResult : ActionResult
+public partial class ChallengeResult : ActionResult
{
///
/// Initializes a new instance of .
@@ -97,8 +98,7 @@ public override async Task ExecuteResultAsync(ActionContext context)
var httpContext = context.HttpContext;
var loggerFactory = httpContext.RequestServices.GetRequiredService();
var logger = loggerFactory.CreateLogger();
-
- logger.ChallengeResultExecuting(AuthenticationSchemes);
+ Log.ChallengeResultExecuting(logger, AuthenticationSchemes);
if (AuthenticationSchemes != null && AuthenticationSchemes.Count > 0)
{
@@ -112,4 +112,18 @@ public override async Task ExecuteResultAsync(ActionContext context)
await httpContext.ChallengeAsync(Properties);
}
}
+
+ private static partial class Log
+ {
+ public static void ChallengeResultExecuting(ILogger logger, IList schemes)
+ {
+ if (logger.IsEnabled(LogLevel.Information))
+ {
+ ChallengeResultExecuting(logger, schemes.ToArray());
+ }
+ }
+
+ [LoggerMessage(1, LogLevel.Information, "Executing ChallengeResult with authentication schemes ({Schemes}).", EventName = "ChallengeResultExecuting", SkipEnabledCheck = true)]
+ private static partial void ChallengeResultExecuting(ILogger logger, string[] schemes);
+ }
}
diff --git a/src/Mvc/Mvc.Core/src/ForbidResult.cs b/src/Mvc/Mvc.Core/src/ForbidResult.cs
index a4ac023e87e0..536fcfca37d4 100644
--- a/src/Mvc/Mvc.Core/src/ForbidResult.cs
+++ b/src/Mvc/Mvc.Core/src/ForbidResult.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Linq;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc;
///
/// An that on execution invokes .
///
-public class ForbidResult : ActionResult
+public partial class ForbidResult : ActionResult
{
///
/// Initializes a new instance of .
@@ -98,8 +99,7 @@ public override async Task ExecuteResultAsync(ActionContext context)
var loggerFactory = httpContext.RequestServices.GetRequiredService();
var logger = loggerFactory.CreateLogger();
-
- logger.ForbidResultExecuting(AuthenticationSchemes);
+ Log.ForbidResultExecuting(logger, AuthenticationSchemes);
if (AuthenticationSchemes != null && AuthenticationSchemes.Count > 0)
{
@@ -113,4 +113,18 @@ public override async Task ExecuteResultAsync(ActionContext context)
await httpContext.ForbidAsync(Properties);
}
}
+
+ private static partial class Log
+ {
+ public static void ForbidResultExecuting(ILogger logger, IList authenticationSchemes)
+ {
+ if (logger.IsEnabled(LogLevel.Information))
+ {
+ ForbidResultExecuting(logger, authenticationSchemes.ToArray());
+ }
+ }
+
+ [LoggerMessage(1, LogLevel.Information, $"Executing {nameof(ForbidResult)} with authentication schemes ({{Schemes}}).", EventName = "ForbidResultExecuting", SkipEnabledCheck = true)]
+ private static partial void ForbidResultExecuting(ILogger logger, string[] schemes);
+ }
}
diff --git a/src/Mvc/Mvc.Core/src/Formatters/FormatFilter.cs b/src/Mvc/Mvc.Core/src/Formatters/FormatFilter.cs
index d0b74ccdc9f1..83d80a6cd2b3 100644
--- a/src/Mvc/Mvc.Core/src/Formatters/FormatFilter.cs
+++ b/src/Mvc/Mvc.Core/src/Formatters/FormatFilter.cs
@@ -110,7 +110,7 @@ public void OnResourceExecuting(ResourceExecutingContext context)
// type than requested e.g. OK if "text/*" requested and action supports "text/plain".
if (!IsSuperSetOfAnySupportedMediaType(contentType, supportedMediaTypes))
{
- _logger.ActionDoesNotSupportFormatFilterContentType(contentType, supportedMediaTypes);
+ Log.ActionDoesNotSupportFormatFilterContentType(_logger, contentType, supportedMediaTypes);
context.Result = new NotFoundResult();
}
}
@@ -185,6 +185,9 @@ private static partial class Log
[LoggerMessage(1, LogLevel.Debug, "Could not find a media type for the format '{FormatFilterContentType}'.", EventName = "UnsupportedFormatFilterContentType")]
public static partial void UnsupportedFormatFilterContentType(ILogger logger, string formatFilterContentType);
+ [LoggerMessage(2, LogLevel.Debug, "Current action does not support the content type '{FormatFilterContentType}'. The supported content types are '{SupportedMediaTypes}'.", EventName = "ActionDoesNotSupportFormatFilterContentType")]
+ public static partial void ActionDoesNotSupportFormatFilterContentType(ILogger logger, string formatFilterContentType, MediaTypeCollection supportedMediaTypes);
+
[LoggerMessage(3, LogLevel.Debug, "Cannot apply content type '{FormatFilterContentType}' to the response as current action had explicitly set a preferred content type.", EventName = "CannotApplyFormatFilterContentType")]
public static partial void CannotApplyFormatFilterContentType(ILogger logger, string formatFilterContentType);
diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/ClientErrorResultFilter.cs b/src/Mvc/Mvc.Core/src/Infrastructure/ClientErrorResultFilter.cs
index e4fddf2cd355..ad32d18f77b3 100644
--- a/src/Mvc/Mvc.Core/src/Infrastructure/ClientErrorResultFilter.cs
+++ b/src/Mvc/Mvc.Core/src/Infrastructure/ClientErrorResultFilter.cs
@@ -1,14 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-#nullable enable
-
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.Infrastructure;
-internal class ClientErrorResultFilter : IAlwaysRunResultFilter, IOrderedFilter
+internal partial class ClientErrorResultFilter : IAlwaysRunResultFilter, IOrderedFilter
{
internal const int FilterOrder = -2000;
private readonly IClientErrorFactory _clientErrorFactory;
@@ -56,7 +54,13 @@ public void OnResultExecuting(ResultExecutingContext context)
return;
}
- _logger.TransformingClientError(context.Result.GetType(), result.GetType(), clientError.StatusCode);
+ Log.TransformingClientError(_logger, context.Result.GetType(), result.GetType(), clientError.StatusCode);
context.Result = result;
}
+
+ private static partial class Log
+ {
+ [LoggerMessage(49, LogLevel.Trace, "Replacing {InitialActionResultType} with status code {StatusCode} with {ReplacedActionResultType}.", EventName = "ClientErrorResultFilter")]
+ public static partial void TransformingClientError(ILogger logger, Type initialActionResultType, Type replacedActionResultType, int? statusCode);
+ }
}
diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/ControllerActionInvoker.cs b/src/Mvc/Mvc.Core/src/Infrastructure/ControllerActionInvoker.cs
index 3824d233a899..d4b5b94a4b1e 100644
--- a/src/Mvc/Mvc.Core/src/Infrastructure/ControllerActionInvoker.cs
+++ b/src/Mvc/Mvc.Core/src/Infrastructure/ControllerActionInvoker.cs
@@ -4,16 +4,18 @@
#nullable enable
using System.Diagnostics;
+using System.Globalization;
using System.Runtime.ExceptionServices;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
using Resources = Microsoft.AspNetCore.Mvc.Core.Resources;
namespace Microsoft.AspNetCore.Mvc.Infrastructure;
-internal class ControllerActionInvoker : ResourceInvoker, IActionInvoker
+internal partial class ControllerActionInvoker : ResourceInvoker, IActionInvoker
{
private readonly ControllerActionInvokerCacheEntry _cacheEntry;
private readonly ControllerContext _controllerContext;
@@ -64,12 +66,10 @@ private Task Next(ref State next, ref Scope scope, ref object? state, ref bool i
var controllerContext = _controllerContext;
_cursor.Reset();
-
- _logger.ExecutingControllerFactory(controllerContext);
+ Log.ExecutingControllerFactory(_logger, controllerContext);
_instance = _cacheEntry.ControllerFactory(controllerContext);
-
- _logger.ExecutedControllerFactory(controllerContext);
+ Log.ExecutedControllerFactory(_logger, controllerContext);
_arguments = new Dictionary(StringComparer.OrdinalIgnoreCase);
@@ -424,7 +424,7 @@ static async Task Logged(ControllerActionInvoker invoker)
controllerContext,
arguments,
controller);
- logger.ActionMethodExecuting(controllerContext, orderedArguments);
+ Log.ActionMethodExecuting(logger, controllerContext, orderedArguments);
var stopwatch = ValueStopwatch.StartNew();
var actionResultValueTask = actionMethodExecutor.Execute(invoker._mapper, objectMethodExecutor, controller!, orderedArguments);
if (actionResultValueTask.IsCompletedSuccessfully)
@@ -437,7 +437,7 @@ static async Task Logged(ControllerActionInvoker invoker)
}
invoker._result = result;
- logger.ActionMethodExecuted(controllerContext, result, stopwatch.GetElapsedTime());
+ Log.ActionMethodExecuted(logger, controllerContext, result, stopwatch.GetElapsedTime());
}
finally
{
@@ -584,4 +584,78 @@ private sealed class ActionExecutedContextSealed : ActionExecutedContext
{
public ActionExecutedContextSealed(ActionContext actionContext, IList filters, object controller) : base(actionContext, filters, controller) { }
}
+
+ // Internal for unit testing
+ internal static new partial class Log
+ {
+ public static void ExecutingControllerFactory(ILogger logger, ControllerContext context)
+ {
+ if (!logger.IsEnabled(LogLevel.Debug))
+ {
+ return;
+ }
+
+ var controllerType = context.ActionDescriptor.ControllerTypeInfo.AsType();
+ var controllerName = TypeNameHelper.GetTypeDisplayName(controllerType);
+ ExecutingControllerFactory(logger, controllerName, controllerType.Assembly.GetName().Name);
+ }
+
+ [LoggerMessage(1, LogLevel.Debug, "Executing controller factory for controller {Controller} ({AssemblyName})", EventName = "ControllerFactoryExecuting", SkipEnabledCheck = true)]
+ private static partial void ExecutingControllerFactory(ILogger logger, string controller, string? assemblyName);
+
+ public static void ExecutedControllerFactory(ILogger logger, ControllerContext context)
+ {
+ if (!logger.IsEnabled(LogLevel.Debug))
+ {
+ return;
+ }
+
+ var controllerType = context.ActionDescriptor.ControllerTypeInfo.AsType();
+ var controllerName = TypeNameHelper.GetTypeDisplayName(controllerType);
+ ExecutedControllerFactory(logger, controllerName, controllerType.Assembly.GetName().Name);
+ }
+
+ [LoggerMessage(2, LogLevel.Debug, "Executed controller factory for controller {Controller} ({AssemblyName})", EventName = "ControllerFactoryExecuted", SkipEnabledCheck = true)]
+ private static partial void ExecutedControllerFactory(ILogger logger, string controller, string? assemblyName);
+
+ public static void ActionMethodExecuting(ILogger logger, ControllerContext context, object?[]? arguments)
+ {
+ if (logger.IsEnabled(LogLevel.Information))
+ {
+ var actionName = context.ActionDescriptor.DisplayName;
+
+ var validationState = context.ModelState.ValidationState;
+ ActionMethodExecuting(logger, actionName, validationState);
+
+ if (arguments != null && logger.IsEnabled(LogLevel.Trace))
+ {
+ var convertedArguments = new string?[arguments.Length];
+ for (var i = 0; i < arguments.Length; i++)
+ {
+ convertedArguments[i] = Convert.ToString(arguments[i], CultureInfo.InvariantCulture);
+ }
+
+ ActionMethodExecutingWithArguments(logger, actionName, convertedArguments);
+ }
+ }
+ }
+
+ [LoggerMessage(101, LogLevel.Information, "Executing action method {ActionName} - Validation state: {ValidationState}", EventName = "ActionMethodExecuting", SkipEnabledCheck = true)]
+ private static partial void ActionMethodExecuting(ILogger logger, string? actionName, ModelValidationState validationState);
+
+ [LoggerMessage(102, LogLevel.Trace, "Executing action method {ActionName} with arguments ({Arguments})", EventName = "ActionMethodExecutingWithArguments", SkipEnabledCheck = true)]
+ private static partial void ActionMethodExecutingWithArguments(ILogger logger, string? actionName, string?[] arguments);
+
+ public static void ActionMethodExecuted(ILogger logger, ControllerContext context, IActionResult result, TimeSpan timeSpan)
+ {
+ if (logger.IsEnabled(LogLevel.Information))
+ {
+ var actionName = context.ActionDescriptor.DisplayName;
+ ActionMethodExecuted(logger, actionName, Convert.ToString(result, CultureInfo.InvariantCulture), timeSpan.TotalMilliseconds);
+ }
+ }
+
+ [LoggerMessage(103, LogLevel.Information, "Executed action method {ActionName}, returned result {ActionResult} in {ElapsedMilliseconds}ms.", EventName = "ActionMethodExecuted", SkipEnabledCheck = true)]
+ private static partial void ActionMethodExecuted(ILogger logger, string? actionName, string? actionResult, double elapsedMilliseconds);
+ }
}
diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/DefaultOutputFormatterSelector.cs b/src/Mvc/Mvc.Core/src/Infrastructure/DefaultOutputFormatterSelector.cs
index fa3e1442d15c..7a5657ddf1c0 100644
--- a/src/Mvc/Mvc.Core/src/Infrastructure/DefaultOutputFormatterSelector.cs
+++ b/src/Mvc/Mvc.Core/src/Infrastructure/DefaultOutputFormatterSelector.cs
@@ -4,6 +4,7 @@
#nullable enable
using System.Collections.ObjectModel;
+using System.Globalization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.Formatters;
@@ -157,7 +158,7 @@ public DefaultOutputFormatterSelector(IOptions options, ILoggerFacto
if (selectedFormatter != null)
{
- _logger.FormatterSelected(selectedFormatter, context);
+ Log.FormatterSelected(_logger, selectedFormatter, context);
}
return selectedFormatter;
@@ -299,6 +300,21 @@ private static void ValidateContentTypes(MediaTypeCollection contentTypes)
private static partial class Log
{
+ public static void FormatterSelected(
+ ILogger logger,
+ IOutputFormatter outputFormatter,
+ OutputFormatterCanWriteContext context)
+ {
+ if (logger.IsEnabled(LogLevel.Debug))
+ {
+ var contentType = Convert.ToString(context.ContentType, CultureInfo.InvariantCulture);
+ FormatterSelected(logger, outputFormatter, contentType);
+ }
+ }
+
+ [LoggerMessage(2, LogLevel.Debug, "Selected output formatter '{OutputFormatter}' and content type '{ContentType}' to write the response.", EventName = "FormatterSelected", SkipEnabledCheck = true)]
+ public static partial void FormatterSelected(ILogger logger, IOutputFormatter outputFormatter, string? contentType);
+
[LoggerMessage(4, LogLevel.Debug, "No information found on request to perform content negotiation.", EventName = "NoAcceptForNegotiation")]
public static partial void NoAcceptForNegotiation(ILogger logger);
diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/FileContentResultExecutor.cs b/src/Mvc/Mvc.Core/src/Infrastructure/FileContentResultExecutor.cs
index 5449a4d98697..734f9b5db03b 100644
--- a/src/Mvc/Mvc.Core/src/Infrastructure/FileContentResultExecutor.cs
+++ b/src/Mvc/Mvc.Core/src/Infrastructure/FileContentResultExecutor.cs
@@ -35,7 +35,7 @@ public virtual Task ExecuteAsync(ActionContext context, FileContentResult result
throw new ArgumentNullException(nameof(result));
}
- Logger.ExecutingFileResult(result);
+ Log.ExecutingFileResult(Logger, result);
var (range, rangeLength, serveBody) = SetHeadersAndLog(
context,
@@ -88,6 +88,18 @@ protected virtual Task WriteFileAsync(ActionContext context, FileContentResult r
private static partial class Log
{
+ public static void ExecutingFileResult(ILogger logger, FileResult fileResult)
+ {
+ if (logger.IsEnabled(LogLevel.Information))
+ {
+ var fileResultType = fileResult.GetType().Name;
+ ExecutingFileResultWithNoFileName(logger, fileResultType, fileResult.FileDownloadName);
+ }
+ }
+
+ [LoggerMessage(2, LogLevel.Information, "Executing {FileResultType}, sending file with download name '{FileDownloadName}' ...", EventName = "ExecutingFileResultWithNoFileName", SkipEnabledCheck = true)]
+ private static partial void ExecutingFileResultWithNoFileName(ILogger logger, string fileResultType, string fileDownloadName);
+
[LoggerMessage(17, LogLevel.Debug, "Writing the requested range of bytes to the body...", EventName = "WritingRangeToBody")]
public static partial void WritingRangeToBody(ILogger logger);
}
diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/FileStreamResultExecutor.cs b/src/Mvc/Mvc.Core/src/Infrastructure/FileStreamResultExecutor.cs
index 51b88f7f223b..8341dca9e367 100644
--- a/src/Mvc/Mvc.Core/src/Infrastructure/FileStreamResultExecutor.cs
+++ b/src/Mvc/Mvc.Core/src/Infrastructure/FileStreamResultExecutor.cs
@@ -37,7 +37,7 @@ public virtual async Task ExecuteAsync(ActionContext context, FileStreamResult r
using (result.FileStream)
{
- Logger.ExecutingFileResult(result);
+ Log.ExecutingFileResult(Logger, result);
long? fileLength = null;
if (result.FileStream.CanSeek)
@@ -100,6 +100,18 @@ protected virtual Task WriteFileAsync(
private static partial class Log
{
+ public static void ExecutingFileResult(ILogger logger, FileResult fileResult)
+ {
+ if (logger.IsEnabled(LogLevel.Information))
+ {
+ var fileResultType = fileResult.GetType().Name;
+ ExecutingFileResultWithNoFileName(logger, fileResultType, fileResult.FileDownloadName);
+ }
+ }
+
+ [LoggerMessage(1, LogLevel.Information, "Executing {FileResultType}, sending file with download name '{FileDownloadName}' ...", EventName = "ExecutingFileResultWithNoFileName", SkipEnabledCheck = true)]
+ private static partial void ExecutingFileResultWithNoFileName(ILogger logger, string fileResultType, string fileDownloadName);
+
[LoggerMessage(17, LogLevel.Debug, "Writing the requested range of bytes to the body...", EventName = "WritingRangeToBody")]
public static partial void WritingRangeToBody(ILogger logger);
}
diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/ModelStateInvalidFilter.cs b/src/Mvc/Mvc.Core/src/Infrastructure/ModelStateInvalidFilter.cs
index 19e5a88fca51..97cae7a7953c 100644
--- a/src/Mvc/Mvc.Core/src/Infrastructure/ModelStateInvalidFilter.cs
+++ b/src/Mvc/Mvc.Core/src/Infrastructure/ModelStateInvalidFilter.cs
@@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure;
/// added to all types and actions annotated with .
/// See for ways to configure this filter.
///
-public class ModelStateInvalidFilter : IActionFilter, IOrderedFilter
+public partial class ModelStateInvalidFilter : IActionFilter, IOrderedFilter
{
internal const int FilterOrder = -2000;
@@ -75,8 +75,14 @@ public void OnActionExecuting(ActionExecutingContext context)
{
if (context.Result == null && !context.ModelState.IsValid)
{
- _logger.ModelStateInvalidFilterExecuting();
+ Log.ModelStateInvalidFilterExecuting(_logger);
context.Result = _apiBehaviorOptions.InvalidModelStateResponseFactory(context);
}
}
+
+ private static partial class Log
+ {
+ [LoggerMessage(1, LogLevel.Debug, "The request has model state errors, returning an error response.", EventName = "ModelStateInvalidFilterExecuting")]
+ public static partial void ModelStateInvalidFilterExecuting(ILogger logger);
+ }
}
diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/ObjectResultExecutor.cs b/src/Mvc/Mvc.Core/src/Infrastructure/ObjectResultExecutor.cs
index 4ffcb0662986..1c4ddb95ab88 100644
--- a/src/Mvc/Mvc.Core/src/Infrastructure/ObjectResultExecutor.cs
+++ b/src/Mvc/Mvc.Core/src/Infrastructure/ObjectResultExecutor.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
+using System.Globalization;
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters;
@@ -13,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure;
///
/// Executes an to write to the response.
///
-public class ObjectResultExecutor : IActionResultExecutor
+public partial class ObjectResultExecutor : IActionResultExecutor
{
///
/// Creates a new .
@@ -111,13 +112,13 @@ private Task ExecuteAsyncCore(ActionContext context, ObjectResult result, Type?
if (selectedFormatter == null)
{
// No formatter supports this.
- Logger.NoFormatter(formatterContext, result.ContentTypes);
+ Log.NoFormatter(Logger, formatterContext, result.ContentTypes);
context.HttpContext.Response.StatusCode = StatusCodes.Status406NotAcceptable;
return Task.CompletedTask;
}
- Logger.ObjectResultExecuting(result, value);
+ Log.ObjectResultExecuting(Logger, result, value);
result.OnFormatting(context);
return selectedFormatter.WriteAsync(formatterContext);
@@ -142,6 +143,41 @@ private static void InferContentTypes(ActionContext context, ObjectResult result
}
}
- // Removed Log.
- // new EventId(1, "BufferingAsyncEnumerable")
+ // Internal for unit testing
+ internal static partial class Log
+ {
+ // Removed Log.
+ // new EventId(1, "BufferingAsyncEnumerable")
+
+ public static void ObjectResultExecuting(ILogger logger, ObjectResult result, object? value)
+ {
+ if (logger.IsEnabled(LogLevel.Information))
+ {
+ var objectResultType = result.GetType().Name;
+ var valueType = value == null ? "null" : value.GetType().FullName;
+ ObjectResultExecuting(logger, objectResultType, valueType);
+ }
+ }
+
+ [LoggerMessage(1, LogLevel.Information, "Executing {ObjectResultType}, writing value of type '{Type}'.", EventName = "ObjectResultExecuting", SkipEnabledCheck = true)]
+ private static partial void ObjectResultExecuting(ILogger logger, string objectResultType, string? type);
+
+ public static void NoFormatter(ILogger logger, OutputFormatterCanWriteContext context, MediaTypeCollection contentTypes)
+ {
+ if (logger.IsEnabled(LogLevel.Warning))
+ {
+ var considered = new List(contentTypes);
+
+ if (context.ContentType.HasValue)
+ {
+ considered.Add(Convert.ToString(context.ContentType, CultureInfo.InvariantCulture));
+ }
+
+ NoFormatter(logger, considered);
+ }
+ }
+
+ [LoggerMessage(2, LogLevel.Warning, "No output formatter was found for content types '{ContentTypes}' to write the response.", EventName = "NoFormatter", SkipEnabledCheck = true)]
+ private static partial void NoFormatter(ILogger logger, List contentTypes);
+ }
}
diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/PhysicalFileResultExecutor.cs b/src/Mvc/Mvc.Core/src/Infrastructure/PhysicalFileResultExecutor.cs
index 887ff1be3a38..4e339c2acf90 100644
--- a/src/Mvc/Mvc.Core/src/Infrastructure/PhysicalFileResultExecutor.cs
+++ b/src/Mvc/Mvc.Core/src/Infrastructure/PhysicalFileResultExecutor.cs
@@ -42,7 +42,7 @@ public virtual Task ExecuteAsync(ActionContext context, PhysicalFileResult resul
Resources.FormatFileResult_InvalidPath(result.FileName), result.FileName);
}
- Logger.ExecutingFileResult(result, result.FileName);
+ Log.ExecutingFileResult(Logger, result, result.FileName);
var lastModified = result.LastModified ?? fileInfo.LastModified;
var (range, rangeLength, serveBody) = SetHeadersAndLog(
@@ -179,6 +179,18 @@ protected class FileMetadata
private static partial class Log
{
+ public static void ExecutingFileResult(ILogger logger, FileResult fileResult, string fileName)
+ {
+ if (logger.IsEnabled(LogLevel.Information))
+ {
+ var fileResultType = fileResult.GetType().Name;
+ ExecutingFileResult(logger, fileResultType, fileName, fileResult.FileDownloadName);
+ }
+ }
+
+ [LoggerMessage(1, LogLevel.Information, "Executing {FileResultType}, sending file '{FileDownloadPath}' with download name '{FileDownloadName}' ...", EventName = "ExecutingFileResult", SkipEnabledCheck = true)]
+ private static partial void ExecutingFileResult(ILogger logger, string fileResultType, string fileDownloadPath, string fileDownloadName);
+
[LoggerMessage(17, LogLevel.Debug, "Writing the requested range of bytes to the body...", EventName = "WritingRangeToBody")]
public static partial void WritingRangeToBody(ILogger logger);
}
diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/ResourceInvoker.Log.cs b/src/Mvc/Mvc.Core/src/Infrastructure/ResourceInvoker.Log.cs
new file mode 100644
index 000000000000..f34b1e5e53e0
--- /dev/null
+++ b/src/Mvc/Mvc.Core/src/Infrastructure/ResourceInvoker.Log.cs
@@ -0,0 +1,119 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using Microsoft.AspNetCore.Mvc.Abstractions;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.Extensions.Internal;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Mvc.Infrastructure;
+
+internal partial class ResourceInvoker
+{
+ // Internal for unit testing
+ internal static partial class Log
+ {
+ public static void ExecutingAction(ILogger logger, ActionDescriptor action)
+ {
+ if (logger.IsEnabled(LogLevel.Information))
+ {
+ var routeKeys = action.RouteValues.Keys.ToArray();
+ var routeValues = action.RouteValues.Values.ToArray();
+ var stringBuilder = new StringBuilder();
+ stringBuilder.Append('{');
+ for (var i = 0; i < routeValues.Length; i++)
+ {
+ if (i == routeValues.Length - 1)
+ {
+ stringBuilder.Append(FormattableString.Invariant($"{routeKeys[i]} = \"{routeValues[i]}\""));
+ }
+ else
+ {
+ stringBuilder.Append(FormattableString.Invariant($"{routeKeys[i]} = \"{routeValues[i]}\", "));
+ }
+ }
+ stringBuilder.Append('}');
+
+ if (action.RouteValues.TryGetValue("page", out var page) && page != null)
+ {
+ PageExecuting(logger, stringBuilder.ToString(), action.DisplayName);
+ }
+ else
+ {
+ if (action is ControllerActionDescriptor controllerActionDescriptor)
+ {
+ var controllerType = controllerActionDescriptor.ControllerTypeInfo.AsType();
+ var controllerName = TypeNameHelper.GetTypeDisplayName(controllerType);
+ ControllerActionExecuting(
+ logger,
+ stringBuilder.ToString(),
+ controllerActionDescriptor.MethodInfo,
+ controllerName,
+ controllerType.Assembly.GetName().Name);
+ }
+ else
+ {
+ ActionExecuting(logger, stringBuilder.ToString(), action.DisplayName);
+ }
+ }
+ }
+ }
+
+ [LoggerMessage(101, LogLevel.Information, "Route matched with {RouteData}. Executing action {ActionName}", EventName = "ActionExecuting", SkipEnabledCheck = true)]
+ private static partial void ActionExecuting(ILogger logger, string routeData, string? actionName);
+
+ [LoggerMessage(102, LogLevel.Information, "Route matched with {RouteData}. Executing controller action with signature {MethodInfo} on controller {Controller} ({AssemblyName}).", EventName = "ControllerActionExecuting", SkipEnabledCheck = true)]
+ private static partial void ControllerActionExecuting(ILogger logger, string routeData, MethodInfo methodInfo, string controller, string? assemblyName);
+
+ [LoggerMessage(103, LogLevel.Information, "Route matched with {RouteData}. Executing page {PageName}", EventName = "PageExecuting", SkipEnabledCheck = true)]
+ private static partial void PageExecuting(ILogger logger, string routeData, string? pageName);
+
+ [LoggerMessage(3, LogLevel.Information, "Authorization failed for the request at filter '{AuthorizationFilter}'.", EventName = "AuthorizationFailure")]
+ public static partial void AuthorizationFailure(ILogger logger, IFilterMetadata authorizationFilter);
+
+ [LoggerMessage(4, LogLevel.Debug, "Request was short circuited at resource filter '{ResourceFilter}'.", EventName = "ResourceFilterShortCircuit")]
+ public static partial void ResourceFilterShortCircuited(ILogger logger, IFilterMetadata resourceFilter);
+
+ [LoggerMessage(5, LogLevel.Trace, "Before executing action result {ActionResult}.", EventName = "BeforeExecutingActionResult")]
+ private static partial void BeforeExecutingActionResult(ILogger logger, Type actionResult);
+
+ public static void BeforeExecutingActionResult(ILogger logger, IActionResult actionResult)
+ {
+ BeforeExecutingActionResult(logger, actionResult.GetType());
+ }
+
+ [LoggerMessage(6, LogLevel.Trace, "After executing action result {ActionResult}.", EventName = "AfterExecutingActionResult")]
+ private static partial void AfterExecutingActionResult(ILogger logger, Type actionResult);
+
+ public static void AfterExecutingActionResult(ILogger logger, IActionResult actionResult)
+ {
+ AfterExecutingActionResult(logger, actionResult.GetType());
+ }
+
+ public static void ExecutedAction(ILogger logger, ActionDescriptor action, TimeSpan timeSpan)
+ {
+ // Don't log if logging wasn't enabled at start of request as time will be wildly wrong.
+ if (logger.IsEnabled(LogLevel.Information))
+ {
+ if (action.RouteValues.TryGetValue("page", out var page) && page != null)
+ {
+ PageExecuted(logger, action.DisplayName, timeSpan.TotalMilliseconds);
+ }
+ else
+ {
+ ActionExecuted(logger, action.DisplayName, timeSpan.TotalMilliseconds);
+ }
+ }
+ }
+
+ [LoggerMessage(104, LogLevel.Information, "Executed page {PageName} in {ElapsedMilliseconds}ms", EventName = "PageExecuted", SkipEnabledCheck = true)]
+ private static partial void PageExecuted(ILogger logger, string? pageName, double elapsedMilliseconds);
+
+ [LoggerMessage(105, LogLevel.Information, "Executed action {ActionName} in {ElapsedMilliseconds}ms", EventName = "ActionExecuted", SkipEnabledCheck = true)]
+ private static partial void ActionExecuted(ILogger logger, string? actionName, double elapsedMilliseconds);
+ }
+}
diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/ResourceInvoker.cs b/src/Mvc/Mvc.Core/src/Infrastructure/ResourceInvoker.cs
index d279ccb1b012..6a1299b883ce 100644
--- a/src/Mvc/Mvc.Core/src/Infrastructure/ResourceInvoker.cs
+++ b/src/Mvc/Mvc.Core/src/Infrastructure/ResourceInvoker.cs
@@ -108,7 +108,7 @@ static async Task Logged(ResourceInvoker invoker)
var actionScope = logger.ActionScope(actionContext.ActionDescriptor);
- logger.ExecutingAction(actionContext.ActionDescriptor);
+ Log.ExecutingAction(logger, actionContext.ActionDescriptor);
var filters = invoker._filters;
logger.AuthorizationFiltersExecutionPlan(filters);
@@ -126,7 +126,7 @@ static async Task Logged(ResourceInvoker invoker)
finally
{
await invoker.ReleaseResourcesCore(actionScope);
- logger.ExecutedAction(actionContext.ActionDescriptor, stopwatch.GetElapsedTime());
+ Log.ExecutedAction(logger, actionContext.ActionDescriptor, stopwatch.GetElapsedTime());
}
}
finally
@@ -1602,29 +1602,4 @@ private sealed class AuthorizationFilterContextSealed : AuthorizationFilterConte
{
public AuthorizationFilterContextSealed(ActionContext actionContext, IList filters) : base(actionContext, filters) { }
}
-
- private static partial class Log
- {
- [LoggerMessage(3, LogLevel.Information, "Authorization failed for the request at filter '{AuthorizationFilter}'.", EventName = "AuthorizationFailure")]
- public static partial void AuthorizationFailure(ILogger logger, IFilterMetadata authorizationFilter);
-
- [LoggerMessage(4, LogLevel.Debug, "Request was short circuited at resource filter '{ResourceFilter}'.", EventName = "ResourceFilterShortCircuit")]
- public static partial void ResourceFilterShortCircuited(ILogger logger, IFilterMetadata resourceFilter);
-
- [LoggerMessage(5, LogLevel.Trace, "Before executing action result {ActionResult}.", EventName = "BeforeExecutingActionResult")]
- private static partial void BeforeExecutingActionResult(ILogger logger, Type actionResult);
-
- public static void BeforeExecutingActionResult(ILogger logger, IActionResult actionResult)
- {
- BeforeExecutingActionResult(logger, actionResult.GetType());
- }
-
- [LoggerMessage(6, LogLevel.Trace, "After executing action result {ActionResult}.", EventName = "AfterExecutingActionResult")]
- private static partial void AfterExecutingActionResult(ILogger logger, Type actionResult);
-
- public static void AfterExecutingActionResult(ILogger logger, IActionResult actionResult)
- {
- AfterExecutingActionResult(logger, actionResult.GetType());
- }
- }
}
diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/VirtualFileResultExecutor.cs b/src/Mvc/Mvc.Core/src/Infrastructure/VirtualFileResultExecutor.cs
index 59c8a0976943..a1a08718e0d9 100644
--- a/src/Mvc/Mvc.Core/src/Infrastructure/VirtualFileResultExecutor.cs
+++ b/src/Mvc/Mvc.Core/src/Infrastructure/VirtualFileResultExecutor.cs
@@ -53,7 +53,7 @@ public virtual Task ExecuteAsync(ActionContext context, VirtualFileResult result
Resources.FormatFileResult_InvalidPath(result.FileName), result.FileName);
}
- Logger.ExecutingFileResult(result, result.FileName);
+ Log.ExecutingFileResult(Logger, result, result.FileName);
var lastModified = result.LastModified ?? fileInfo.LastModified;
var (range, rangeLength, serveBody) = SetHeadersAndLog(
@@ -161,6 +161,18 @@ protected virtual Stream GetFileStream(IFileInfo fileInfo)
private static partial class Log
{
+ public static void ExecutingFileResult(ILogger logger, FileResult fileResult, string fileName)
+ {
+ if (logger.IsEnabled(LogLevel.Information))
+ {
+ var fileResultType = fileResult.GetType().Name;
+ ExecutingFileResult(logger, fileResultType, fileName, fileResult.FileDownloadName);
+ }
+ }
+
+ [LoggerMessage(1, LogLevel.Information, "Executing {FileResultType}, sending file '{FileDownloadPath}' with download name '{FileDownloadName}' ...", EventName = "ExecutingFileResult", SkipEnabledCheck = true)]
+ private static partial void ExecutingFileResult(ILogger logger, string fileResultType, string fileDownloadPath, string fileDownloadName);
+
[LoggerMessage(17, LogLevel.Debug, "Writing the requested range of bytes to the body...", EventName = "WritingRangeToBody")]
public static partial void WritingRangeToBody(ILogger logger);
}
diff --git a/src/Mvc/Mvc.Core/src/ModelBinding/Binders/BodyModelBinder.cs b/src/Mvc/Mvc.Core/src/ModelBinding/Binders/BodyModelBinder.cs
index 0227ad2f78e1..5ce406fbc876 100644
--- a/src/Mvc/Mvc.Core/src/ModelBinding/Binders/BodyModelBinder.cs
+++ b/src/Mvc/Mvc.Core/src/ModelBinding/Binders/BodyModelBinder.cs
@@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
/// An which binds models from the request body using an
/// when a model has the binding source .
///
-public class BodyModelBinder : IModelBinder
+public partial class BodyModelBinder : IModelBinder
{
private readonly IList _formatters;
private readonly Func _readerFactory;
@@ -129,12 +129,12 @@ public async Task BindModelAsync(ModelBindingContext bindingContext)
if (_formatters[i].CanRead(formatterContext))
{
formatter = _formatters[i];
- _logger.InputFormatterSelected(formatter, formatterContext);
+ Log.InputFormatterSelected(_logger, formatter, formatterContext);
break;
}
else
{
- _logger.InputFormatterRejected(_formatters[i], formatterContext);
+ Log.InputFormatterRejected(_logger, _formatters[i], formatterContext);
}
}
@@ -151,7 +151,7 @@ public async Task BindModelAsync(ModelBindingContext bindingContext)
}
}
- _logger.NoInputFormatterSelected(formatterContext);
+ Log.NoInputFormatterSelected(_logger, formatterContext);
var message = Resources.FormatUnsupportedContentType(httpContext.Request.ContentType);
var exception = new UnsupportedContentTypeException(message);
@@ -206,4 +206,52 @@ private static bool ShouldHandleException(IInputFormatter formatter)
return policy == InputFormatterExceptionPolicy.AllExceptions;
}
+
+ private partial class Log
+ {
+ public static void InputFormatterSelected(ILogger logger, IInputFormatter inputFormatter, InputFormatterContext formatterContext)
+ {
+ if (logger.IsEnabled(LogLevel.Debug))
+ {
+ var contentType = formatterContext.HttpContext.Request.ContentType;
+ InputFormatterSelected(logger, inputFormatter, contentType);
+ }
+ }
+
+ [LoggerMessage(1, LogLevel.Debug, "Selected input formatter '{InputFormatter}' for content type '{ContentType}'.", EventName = "InputFormatterSelected", SkipEnabledCheck = true)]
+ private static partial void InputFormatterSelected(ILogger logger, IInputFormatter inputFormatter, string? contentType);
+
+ public static void InputFormatterRejected(ILogger logger, IInputFormatter inputFormatter, InputFormatterContext formatterContext)
+ {
+ if (logger.IsEnabled(LogLevel.Debug))
+ {
+ var contentType = formatterContext.HttpContext.Request.ContentType;
+ InputFormatterRejected(logger, inputFormatter, contentType);
+ }
+ }
+
+ [LoggerMessage(2, LogLevel.Debug, "Rejected input formatter '{InputFormatter}' for content type '{ContentType}'.", EventName = "InputFormatterRejected", SkipEnabledCheck = true)]
+ private static partial void InputFormatterRejected(ILogger logger, IInputFormatter inputFormatter, string? contentType);
+
+ public static void NoInputFormatterSelected(ILogger logger, InputFormatterContext formatterContext)
+ {
+ if (logger.IsEnabled(LogLevel.Debug))
+ {
+ var contentType = formatterContext.HttpContext.Request.ContentType;
+ NoInputFormatterSelected(logger, contentType);
+ if (formatterContext.HttpContext.Request.HasFormContentType)
+ {
+ var modelType = formatterContext.ModelType.FullName;
+ var modelName = formatterContext.ModelName;
+ RemoveFromBodyAttribute(logger, modelName, modelType);
+ }
+ }
+ }
+
+ [LoggerMessage(3, LogLevel.Debug, "No input formatter was found to support the content type '{ContentType}' for use with the [FromBody] attribute.", EventName = "NoInputFormatterSelected", SkipEnabledCheck = true)]
+ private static partial void NoInputFormatterSelected(ILogger logger, string? contentType);
+
+ [LoggerMessage(4, LogLevel.Debug, "To use model binding, remove the [FromBody] attribute from the property or parameter named '{ModelName}' with model type '{ModelType}'.", EventName = "RemoveFromBodyAttribute", SkipEnabledCheck = true)]
+ private static partial void RemoveFromBodyAttribute(ILogger logger, string modelName, string? modelType);
+ }
}
diff --git a/src/Mvc/Mvc.Core/src/ModelBinding/Binders/CollectionModelBinder.cs b/src/Mvc/Mvc.Core/src/ModelBinding/Binders/CollectionModelBinder.cs
index b00944ddf766..116c6f6c66dc 100644
--- a/src/Mvc/Mvc.Core/src/ModelBinding/Binders/CollectionModelBinder.cs
+++ b/src/Mvc/Mvc.Core/src/ModelBinding/Binders/CollectionModelBinder.cs
@@ -11,6 +11,7 @@
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
@@ -18,7 +19,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
/// implementation for binding collection values.
///
/// Type of elements in the collection.
-public class CollectionModelBinder : ICollectionModelBinder
+public partial class CollectionModelBinder : ICollectionModelBinder
{
private static readonly IValueProvider EmptyValueProvider = new CompositeValueProvider();
private readonly int _maxModelBindingCollectionSize = MvcOptions.DefaultMaxModelBindingCollectionSize;
@@ -151,7 +152,7 @@ public virtual async Task BindModelAsync(ModelBindingContext bindingContext)
CollectionResult result;
if (valueProviderResult == ValueProviderResult.None)
{
- Logger.NoNonIndexBasedFormatFoundForCollection(bindingContext);
+ Log.NoNonIndexBasedFormatFoundForCollection(Logger, bindingContext);
result = await BindComplexCollection(bindingContext);
}
else
@@ -305,7 +306,7 @@ internal async Task BindSimpleCollection(
// Used when the ValueProvider contains the collection to be bound as multiple elements, e.g. foo[0], foo[1].
private Task BindComplexCollection(ModelBindingContext bindingContext)
{
- Logger.AttemptingToBindCollectionUsingIndices(bindingContext);
+ Log.AttemptingToBindCollectionUsingIndices(Logger, bindingContext);
var indexPropertyName = ModelNames.CreatePropertyModelName(bindingContext.ModelName, "index");
@@ -486,4 +487,54 @@ protected virtual void CopyToModel(object target, IEnumerable sourceC
var indexes = (string[]?)valueProviderResult;
return (indexes == null || indexes.Length == 0) ? null : indexes;
}
+
+ private static partial class Log
+ {
+ public static void AttemptingToBindCollectionUsingIndices(ILogger logger, ModelBindingContext bindingContext)
+ {
+ if (!logger.IsEnabled(LogLevel.Debug))
+ {
+ return;
+ }
+
+ var modelName = bindingContext.ModelName;
+
+ var enumerableType = ClosedGenericMatcher.ExtractGenericInterface(bindingContext.ModelType, typeof(IEnumerable<>));
+ if (enumerableType != null)
+ {
+ var elementType = enumerableType.GenericTypeArguments[0];
+ if (elementType.IsGenericType && elementType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>))
+ {
+ AttemptingToBindCollectionOfKeyValuePair(logger, modelName);
+ return;
+ }
+ }
+
+ AttemptingToBindCollectionUsingIndices(logger, modelName);
+ }
+
+ [LoggerMessage(29, LogLevel.Debug,
+ "Attempting to bind model using indices. Example formats include: " +
+ "[0]=value1&[1]=value2, " +
+ "{ModelName}[0]=value1&{ModelName}[1]=value2, " +
+ "{ModelName}.index=zero&{ModelName}.index=one&{ModelName}[zero]=value1&{ModelName}[one]=value2",
+ EventName = "AttemptingToBindCollectionUsingIndices",
+ SkipEnabledCheck = true)]
+ private static partial void AttemptingToBindCollectionUsingIndices(ILogger logger, string modelName);
+
+ [LoggerMessage(30, LogLevel.Debug,
+ "Attempting to bind collection of KeyValuePair. Example formats include: " +
+ "[0].Key=key1&[0].Value=value1&[1].Key=key2&[1].Value=value2, " +
+ "{ModelName}[0].Key=key1&{ModelName}[0].Value=value1&{ModelName}[1].Key=key2&{ModelName}[1].Value=value2, " +
+ "{ModelName}[key1]=value1&{ModelName}[key2]=value2",
+ EventName = "AttemptingToBindCollectionOfKeyValuePair",
+ SkipEnabledCheck = true)]
+ private static partial void AttemptingToBindCollectionOfKeyValuePair(ILogger logger, string modelName);
+
+ public static void NoNonIndexBasedFormatFoundForCollection(ILogger logger, ModelBindingContext bindingContext)
+ => NoNonIndexBasedFormatFoundForCollection(logger, bindingContext.ModelName);
+
+ [LoggerMessage(28, LogLevel.Debug, "Could not bind to collection using a format like {ModelName}=value1&{ModelName}=value2", EventName = "NoNonIndexBasedFormatFoundForCollection")]
+ private static partial void NoNonIndexBasedFormatFoundForCollection(ILogger logger, string modelName);
+ }
}
diff --git a/src/Mvc/Mvc.Core/src/ModelBinding/Binders/ComplexObjectModelBinder.cs b/src/Mvc/Mvc.Core/src/ModelBinding/Binders/ComplexObjectModelBinder.cs
index 51c494f812d5..b3740b533758 100644
--- a/src/Mvc/Mvc.Core/src/ModelBinding/Binders/ComplexObjectModelBinder.cs
+++ b/src/Mvc/Mvc.Core/src/ModelBinding/Binders/ComplexObjectModelBinder.cs
@@ -656,7 +656,7 @@ private int CanBindAnyModelItem(ModelBindingContext bindingContext)
return GreedyPropertiesMayHaveData;
}
- _logger.CannotBindToComplexType(bindingContext);
+ Log.CannotBindToComplexType(_logger, bindingContext);
return NoDataAvailable;
}
@@ -747,5 +747,11 @@ public static void NoPublicSettableItems(ILogger logger, ModelBindingContext bin
{
NoPublicSettableItems(logger, bindingContext.ModelName, bindingContext.ModelType);
}
+
+ public static void CannotBindToComplexType(ILogger logger, ModelBindingContext bindingContext)
+ => CannotBindToComplexType(logger, bindingContext.ModelType);
+
+ [LoggerMessage(18, LogLevel.Debug, "Could not bind to model of type '{ModelType}' as there were no values in the request for any of the properties.", EventName = "CannotBindToComplexType")]
+ private static partial void CannotBindToComplexType(ILogger logger, Type modelType);
}
}
diff --git a/src/Mvc/Mvc.Core/src/ModelBinding/Binders/ComplexTypeModelBinder.cs b/src/Mvc/Mvc.Core/src/ModelBinding/Binders/ComplexTypeModelBinder.cs
index 606cf3ab5182..c72769f52cd9 100644
--- a/src/Mvc/Mvc.Core/src/ModelBinding/Binders/ComplexTypeModelBinder.cs
+++ b/src/Mvc/Mvc.Core/src/ModelBinding/Binders/ComplexTypeModelBinder.cs
@@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
/// implementation for binding complex types.
///
[Obsolete("This type is obsolete and will be removed in a future version. Use ComplexObjectModelBinder instead.")]
-public class ComplexTypeModelBinder : IModelBinder
+public partial class ComplexTypeModelBinder : IModelBinder
{
// Don't want a new public enum because communication between the private and internal methods of this class
// should not be exposed. Can't use an internal enum because types of [TheoryData] values must be public.
@@ -358,7 +358,7 @@ private int CanBindAnyModelProperties(ModelBindingContext bindingContext)
// level object. So we return false.
if (bindingContext.ModelMetadata.Properties.Count == 0)
{
- _logger.NoPublicSettableProperties(bindingContext);
+ Log.NoPublicSettableProperties(_logger, bindingContext);
return NoDataAvailable;
}
@@ -424,7 +424,7 @@ private int CanBindAnyModelProperties(ModelBindingContext bindingContext)
return GreedyPropertiesMayHaveData;
}
- _logger.CannotBindToComplexType(bindingContext);
+ Log.CannotBindToComplexType(_logger, bindingContext);
return NoDataAvailable;
}
@@ -592,4 +592,19 @@ private static void AddModelError(
modelState.AddModelError(modelName, exception, bindingContext.ModelMetadata);
}
}
+
+ private static partial class Log
+ {
+ public static void NoPublicSettableProperties(ILogger logger, ModelBindingContext bindingContext)
+ => NoPublicSettableProperties(logger, bindingContext.ModelName, bindingContext.ModelType);
+
+ [LoggerMessage(17, LogLevel.Debug, "Could not bind to model with name '{ModelName}' and type '{ModelType}' as the type has no public settable properties.", EventName = "NoPublicSettableProperties")]
+ private static partial void NoPublicSettableProperties(ILogger logger, string modelName, Type modelType);
+
+ public static void CannotBindToComplexType(ILogger logger, ModelBindingContext bindingContext)
+ => CannotBindToComplexType(logger, bindingContext.ModelType);
+
+ [LoggerMessage(18, LogLevel.Debug, "Could not bind to model of type '{ModelType}' as there were no values in the request for any of the properties.", EventName = "CannotBindToComplexType")]
+ private static partial void CannotBindToComplexType(ILogger logger, Type modelType);
+ }
}
diff --git a/src/Mvc/Mvc.Core/src/ModelBinding/Binders/DictionaryModelBinder.cs b/src/Mvc/Mvc.Core/src/ModelBinding/Binders/DictionaryModelBinder.cs
index 6af4fbf9c95a..36c97f95236f 100644
--- a/src/Mvc/Mvc.Core/src/ModelBinding/Binders/DictionaryModelBinder.cs
+++ b/src/Mvc/Mvc.Core/src/ModelBinding/Binders/DictionaryModelBinder.cs
@@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
///
/// Type of keys in the dictionary.
/// Type of values in the dictionary.
-public class DictionaryModelBinder : CollectionModelBinder> where TKey : notnull
+public partial class DictionaryModelBinder : CollectionModelBinder> where TKey : notnull
{
private readonly IModelBinder _valueBinder;
@@ -140,7 +140,7 @@ public override async Task BindModelAsync(ModelBindingContext bindingContext)
return;
}
- Logger.NoKeyValueFormatForDictionaryModelBinder(bindingContext);
+ Log.NoKeyValueFormatForDictionaryModelBinder(Logger, bindingContext);
if (bindingContext.ValueProvider is not IEnumerableValueProvider enumerableValueProvider)
{
@@ -262,4 +262,13 @@ public override bool CanCreateInstance(Type targetType)
return base.CanCreateInstance(targetType);
}
+
+ private static partial class Log
+ {
+ public static void NoKeyValueFormatForDictionaryModelBinder(ILogger logger, ModelBindingContext bindingContext)
+ => NoKeyValueFormatForDictionaryModelBinder(logger, bindingContext.ModelName);
+
+ [LoggerMessage(33, LogLevel.Debug, "Attempting to bind model with name '{ModelName}' using the format {ModelName}[key1]=value1&{ModelName}[key2]=value2", EventName = "NoKeyValueFormatForDictionaryModelBinder")]
+ private static partial void NoKeyValueFormatForDictionaryModelBinder(ILogger logger, string modelName);
+ }
}
diff --git a/src/Mvc/Mvc.Core/src/ModelBinding/ParameterBinder.Log.cs b/src/Mvc/Mvc.Core/src/ModelBinding/ParameterBinder.Log.cs
new file mode 100644
index 000000000000..7c0dd27a63fc
--- /dev/null
+++ b/src/Mvc/Mvc.Core/src/ModelBinding/ParameterBinder.Log.cs
@@ -0,0 +1,255 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.AspNetCore.Mvc.Abstractions;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Mvc.ModelBinding;
+
+public partial class ParameterBinder
+{
+ private static partial class Log
+ {
+ public static void AttemptingToBindParameterOrProperty(
+ ILogger logger,
+ ParameterDescriptor parameter,
+ ModelMetadata modelMetadata)
+ {
+ if (!logger.IsEnabled(LogLevel.Debug))
+ {
+ return;
+ }
+
+ switch (modelMetadata.MetadataKind)
+ {
+ case ModelMetadataKind.Parameter:
+ AttemptingToBindParameter(logger, modelMetadata.ParameterName, modelMetadata.ModelType);
+ break;
+ case ModelMetadataKind.Property:
+ AttemptingToBindProperty(
+ logger,
+ modelMetadata.ContainerType,
+ modelMetadata.PropertyName,
+ modelMetadata.ModelType);
+ break;
+ case ModelMetadataKind.Type:
+ if (parameter is ControllerParameterDescriptor parameterDescriptor)
+ {
+ AttemptingToBindParameter(
+ logger,
+ parameterDescriptor.ParameterInfo.Name,
+ modelMetadata.ModelType);
+ }
+ else
+ {
+ // Likely binding a page handler parameter. Due to various special cases, parameter.Name may
+ // be empty. No way to determine actual name.
+ AttemptingToBindParameter(logger, parameter.Name, modelMetadata.ModelType);
+ }
+ break;
+ }
+ }
+
+ [LoggerMessage(22, LogLevel.Debug, "Attempting to bind parameter '{ParameterName}' of type '{ModelType}' ...", EventName = "AttemptingToBindParameter", SkipEnabledCheck = true)]
+ private static partial void AttemptingToBindParameter(ILogger logger, string? parameterName, Type modelType);
+
+ [LoggerMessage(39, LogLevel.Debug, "Attempting to bind property '{PropertyContainerType}.{PropertyName}' of type '{ModelType}' ...", EventName = "AttemptingToBindProperty", SkipEnabledCheck = true)]
+ private static partial void AttemptingToBindProperty(ILogger logger, Type? propertyContainerType, string? propertyName, Type modelType);
+
+ public static void DoneAttemptingToBindParameterOrProperty(
+ ILogger logger,
+ ParameterDescriptor parameter,
+ ModelMetadata modelMetadata)
+ {
+ if (!logger.IsEnabled(LogLevel.Debug))
+ {
+ return;
+ }
+
+ switch (modelMetadata.MetadataKind)
+ {
+ case ModelMetadataKind.Parameter:
+ DoneAttemptingToBindParameter(logger, modelMetadata.ParameterName, modelMetadata.ModelType);
+ break;
+ case ModelMetadataKind.Property:
+ DoneAttemptingToBindProperty(
+ logger,
+ modelMetadata.ContainerType,
+ modelMetadata.PropertyName,
+ modelMetadata.ModelType);
+ break;
+ case ModelMetadataKind.Type:
+ if (parameter is ControllerParameterDescriptor parameterDescriptor)
+ {
+ DoneAttemptingToBindParameter(
+ logger,
+ parameterDescriptor.ParameterInfo.Name,
+ modelMetadata.ModelType);
+ }
+ else
+ {
+ // Likely binding a page handler parameter. Due to various special cases, parameter.Name may
+ // be empty. No way to determine actual name.
+ DoneAttemptingToBindParameter(logger, parameter.Name, modelMetadata.ModelType);
+ }
+ break;
+ }
+ }
+
+ [LoggerMessage(23, LogLevel.Debug, "Done attempting to bind parameter '{ParameterName}' of type '{ModelType}'.", EventName = "DoneAttemptingToBindParameter", SkipEnabledCheck = true)]
+ private static partial void DoneAttemptingToBindParameter(ILogger logger, string? parameterName, Type modelType);
+
+ [LoggerMessage(40, LogLevel.Debug, "Done attempting to bind property '{PropertyContainerType}.{PropertyName}' of type '{ModelType}'.", EventName = "DoneAttemptingToBindProperty", SkipEnabledCheck = true)]
+ private static partial void DoneAttemptingToBindProperty(ILogger logger, Type? propertyContainerType, string? propertyName, Type modelType);
+
+ public static void AttemptingToValidateParameterOrProperty(
+ ILogger logger,
+ ParameterDescriptor parameter,
+ ModelMetadata modelMetadata)
+ {
+ if (!logger.IsEnabled(LogLevel.Debug))
+ {
+ return;
+ }
+
+ switch (modelMetadata.MetadataKind)
+ {
+ case ModelMetadataKind.Parameter:
+ AttemptingToValidateParameter(logger, modelMetadata.ParameterName, modelMetadata.ModelType);
+ break;
+ case ModelMetadataKind.Property:
+ AttemptingToValidateProperty(
+ logger,
+ modelMetadata.ContainerType,
+ modelMetadata.PropertyName,
+ modelMetadata.ModelType);
+ break;
+ case ModelMetadataKind.Type:
+ if (parameter is ControllerParameterDescriptor parameterDescriptor)
+ {
+ AttemptingToValidateParameter(
+ logger,
+ parameterDescriptor.ParameterInfo.Name,
+ modelMetadata.ModelType);
+ }
+ else
+ {
+ // Likely binding a page handler parameter. Due to various special cases, parameter.Name may
+ // be empty. No way to determine actual name. This case is less likely than for binding logging
+ // (above). Should occur only with a legacy IModelMetadataProvider implementation.
+ AttemptingToValidateParameter(logger, parameter.Name, modelMetadata.ModelType);
+ }
+ break;
+ }
+ }
+
+ [LoggerMessage(26, LogLevel.Debug, "Attempting to validate the bound parameter '{ParameterName}' of type '{ModelType}' ...", EventName = "AttemptingToValidateParameter", SkipEnabledCheck = true)]
+ private static partial void AttemptingToValidateParameter(ILogger logger, string? parameterName, Type modelType);
+
+ [LoggerMessage(41, LogLevel.Debug, "Attempting to validate the bound property '{PropertyContainerType}.{PropertyName}' of type '{ModelType}' ...", EventName = "AttemptingToValidateProperty", SkipEnabledCheck = true)]
+ private static partial void AttemptingToValidateProperty(ILogger logger, Type? propertyContainerType, string? propertyName, Type modelType);
+
+ public static void DoneAttemptingToValidateParameterOrProperty(
+ ILogger logger,
+ ParameterDescriptor parameter,
+ ModelMetadata modelMetadata)
+ {
+ if (!logger.IsEnabled(LogLevel.Debug))
+ {
+ return;
+ }
+
+ switch (modelMetadata.MetadataKind)
+ {
+ case ModelMetadataKind.Parameter:
+ DoneAttemptingToValidateParameter(
+ logger,
+ modelMetadata.ParameterName,
+ modelMetadata.ModelType);
+ break;
+ case ModelMetadataKind.Property:
+ DoneAttemptingToValidateProperty(
+ logger,
+ modelMetadata.ContainerType,
+ modelMetadata.PropertyName,
+ modelMetadata.ModelType);
+ break;
+ case ModelMetadataKind.Type:
+ if (parameter is ControllerParameterDescriptor parameterDescriptor)
+ {
+ DoneAttemptingToValidateParameter(
+ logger,
+ parameterDescriptor.ParameterInfo.Name,
+ modelMetadata.ModelType);
+ }
+ else
+ {
+ // Likely binding a page handler parameter. Due to various special cases, parameter.Name may
+ // be empty. No way to determine actual name. This case is less likely than for binding logging
+ // (above). Should occur only with a legacy IModelMetadataProvider implementation.
+ DoneAttemptingToValidateParameter(logger, parameter.Name, modelMetadata.ModelType);
+ }
+ break;
+ }
+ }
+
+ [LoggerMessage(27, LogLevel.Debug, "Done attempting to validate the bound parameter '{ParameterName}' of type '{ModelType}'.", EventName = "DoneAttemptingToValidateParameter")]
+ private static partial void DoneAttemptingToValidateParameter(ILogger logger, string? parameterName, Type modelType);
+
+ [LoggerMessage(42, LogLevel.Debug, "Done attempting to validate the bound property '{PropertyContainerType}.{PropertyName}' of type '{ModelType}'.", EventName = "DoneAttemptingToValidateProperty")]
+ private static partial void DoneAttemptingToValidateProperty(ILogger logger, Type? propertyContainerType, string? propertyName, Type modelType);
+
+ public static void ParameterBinderRequestPredicateShortCircuit(
+ ILogger logger,
+ ParameterDescriptor parameter,
+ ModelMetadata modelMetadata)
+ {
+ if (!logger.IsEnabled(LogLevel.Debug))
+ {
+ return;
+ }
+
+ switch (modelMetadata.MetadataKind)
+ {
+ case ModelMetadataKind.Parameter:
+ ParameterBinderRequestPredicateShortCircuitOfParameter(
+ logger,
+ modelMetadata.ParameterName);
+ break;
+ case ModelMetadataKind.Property:
+ ParameterBinderRequestPredicateShortCircuitOfProperty(
+ logger,
+ modelMetadata.ContainerType,
+ modelMetadata.PropertyName);
+ break;
+ case ModelMetadataKind.Type:
+ if (parameter is ControllerParameterDescriptor controllerParameterDescriptor)
+ {
+ ParameterBinderRequestPredicateShortCircuitOfParameter(
+ logger,
+ controllerParameterDescriptor.ParameterInfo.Name);
+ }
+ else
+ {
+ // Likely binding a page handler parameter. Due to various special cases, parameter.Name may
+ // be empty. No way to determine actual name. This case is less likely than for binding logging
+ // (above). Should occur only with a legacy IModelMetadataProvider implementation.
+ ParameterBinderRequestPredicateShortCircuitOfParameter(logger, parameter.Name);
+ }
+ break;
+ }
+ }
+
+ [LoggerMessage(47, LogLevel.Debug, "Skipped binding property '{PropertyContainerType}.{PropertyName}' since its binding information disallowed it for the current request.",
+ EventName = "ParameterBinderRequestPredicateShortCircuitOfProperty",
+ SkipEnabledCheck = true)]
+ private static partial void ParameterBinderRequestPredicateShortCircuitOfProperty(ILogger logger, Type? propertyContainerType, string? propertyName);
+
+ [LoggerMessage(48, LogLevel.Debug, "Skipped binding parameter '{ParameterName}' since its binding information disallowed it for the current request.",
+ EventName = "ParameterBinderRequestPredicateShortCircuitOfParameter",
+ SkipEnabledCheck = true)]
+ private static partial void ParameterBinderRequestPredicateShortCircuitOfParameter(ILogger logger, string? parameterName);
+ }
+}
diff --git a/src/Mvc/Mvc.Core/src/ModelBinding/ParameterBinder.cs b/src/Mvc/Mvc.Core/src/ModelBinding/ParameterBinder.cs
index 6ba93782b356..54386437510f 100644
--- a/src/Mvc/Mvc.Core/src/ModelBinding/ParameterBinder.cs
+++ b/src/Mvc/Mvc.Core/src/ModelBinding/ParameterBinder.cs
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-#nullable enable
-
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
@@ -14,7 +12,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding;
///
/// Binds and validates models specified by a .
///
-public class ParameterBinder
+public partial class ParameterBinder
{
private readonly IModelMetadataProvider _modelMetadataProvider;
private readonly IModelBinderFactory _modelBinderFactory;
@@ -136,11 +134,11 @@ public virtual async ValueTask BindModelAsync(
throw new ArgumentNullException(nameof(metadata));
}
- Logger.AttemptingToBindParameterOrProperty(parameter, metadata);
+ Log.AttemptingToBindParameterOrProperty(Logger, parameter, metadata);
if (parameter.BindingInfo?.RequestPredicate?.Invoke(actionContext) == false)
{
- Logger.ParameterBinderRequestPredicateShortCircuit(parameter, metadata);
+ Log.ParameterBinderRequestPredicateShortCircuit(Logger, parameter, metadata);
return ModelBindingResult.Failed();
}
@@ -171,13 +169,13 @@ public virtual async ValueTask BindModelAsync(
await modelBinder.BindModelAsync(modelBindingContext);
- Logger.DoneAttemptingToBindParameterOrProperty(parameter, metadata);
+ Log.DoneAttemptingToBindParameterOrProperty(Logger, parameter, metadata);
var modelBindingResult = modelBindingContext.Result;
if (_objectModelValidator is ObjectModelValidator baseObjectValidator)
{
- Logger.AttemptingToValidateParameterOrProperty(parameter, metadata);
+ Log.AttemptingToValidateParameterOrProperty(Logger, parameter, metadata);
EnforceBindRequiredAndValidate(
baseObjectValidator,
@@ -188,7 +186,7 @@ public virtual async ValueTask BindModelAsync(
modelBindingResult,
container);
- Logger.DoneAttemptingToValidateParameterOrProperty(parameter, metadata);
+ Log.DoneAttemptingToValidateParameterOrProperty(Logger, parameter, metadata);
}
else
{
diff --git a/src/Mvc/Mvc.Core/src/MvcCoreLoggerExtensions.cs b/src/Mvc/Mvc.Core/src/MvcCoreLoggerExtensions.cs
index b7d96bbad69e..cd8c3885931e 100644
--- a/src/Mvc/Mvc.Core/src/MvcCoreLoggerExtensions.cs
+++ b/src/Mvc/Mvc.Core/src/MvcCoreLoggerExtensions.cs
@@ -1,24 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-#nullable disable
-#pragma warning disable CA1810 // Initialize all static fields inline.
-
using System.Collections;
using System.Globalization;
using System.Linq;
-using System.Reflection;
-using System.Text;
using Microsoft.AspNetCore.Mvc.Abstractions;
-using Microsoft.AspNetCore.Mvc.ApplicationModels;
-using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
-using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
-using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
-using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Mvc;
@@ -27,486 +17,11 @@ internal static partial class MvcCoreLoggerExtensions
public const string ActionFilter = "Action Filter";
private static readonly string[] _noFilters = new[] { "None" };
- private static readonly Action _controllerFactoryExecuting;
- private static readonly Action _controllerFactoryExecuted;
-
- private static readonly Action _actionExecuting;
- private static readonly Action _controllerActionExecuting;
- private static readonly Action _actionExecuted;
-
- private static readonly Action _pageExecuting;
- private static readonly Action _pageExecuted;
-
- private static readonly Action _challengeResultExecuting;
- private static readonly Action _actionMethodExecuting;
- private static readonly Action _actionMethodExecutingWithArguments;
- private static readonly Action _actionMethodExecuted;
-
- private static readonly Action _logFilterExecutionPlan;
- private static readonly Action _beforeExecutingMethodOnFilter;
- private static readonly Action _afterExecutingMethodOnFilter;
- private static readonly Action _executingFileResult;
- private static readonly Action _executingFileResultWithNoFileName;
- private static readonly Action _resultFilterShortCircuit;
- private static readonly Action _actionFilterShortCircuit;
- private static readonly Action _exceptionFilterShortCircuit;
-
- private static readonly Action _forbidResultExecuting;
- private static readonly Action _signOutResultExecuting;
- private static readonly Action _objectResultExecuting;
- private static readonly Action, Exception> _noFormatter;
- private static readonly Action _formatterSelected;
- private static readonly Action _inputFormatterSelected;
- private static readonly Action _inputFormatterRejected;
- private static readonly Action _noInputFormatterSelected;
- private static readonly Action _removeFromBodyAttribute;
- private static readonly Action _noActionsMatched;
- private static readonly Action _modelStateInvalidFilterExecuting;
-
- private static readonly Action _inferredParameterSource;
- private static readonly Action _foundNoValueForPropertyInRequest;
- private static readonly Action _foundNoValueForParameterInRequest;
- private static readonly Action _foundNoValueInRequest;
- private static readonly Action _parameterBinderRequestPredicateShortCircuitOfProperty;
- private static readonly Action _parameterBinderRequestPredicateShortCircuitOfParameter;
- private static readonly Action _noPublicSettableProperties;
- private static readonly Action _cannotBindToComplexType;
- private static readonly Action _cannotBindToFilesCollectionDueToUnsupportedContentType;
- private static readonly Action _cannotCreateHeaderModelBinderCompatVersion_2_0;
- private static readonly Action _noNonIndexBasedFormatFoundForCollection;
- private static readonly Action _attemptingToBindCollectionUsingIndices;
- private static readonly Action _attemptingToBindCollectionOfKeyValuePair;
- private static readonly Action _noKeyValueFormatForDictionaryModelBinder;
- private static readonly Action _attemptingToBindParameterModel;
- private static readonly Action _doneAttemptingToBindParameterModel;
- private static readonly Action _attemptingToBindPropertyModel;
- private static readonly Action _doneAttemptingToBindPropertyModel;
- private static readonly Action _attemptingToBindModel;
- private static readonly Action _doneAttemptingToBindModel;
- private static readonly Action _attemptingToBindParameter;
- private static readonly Action _doneAttemptingToBindParameter;
- private static readonly Action _attemptingToBindProperty;
- private static readonly Action _doneAttemptingToBindProperty;
- private static readonly Action _attemptingToValidateProperty;
- private static readonly Action _doneAttemptingToValidateProperty;
- private static readonly Action _attemptingToValidateParameter;
- private static readonly Action _doneAttemptingToValidateParameter;
- private static readonly Action _actionDoesNotSupportFormatFilterContentType;
- private static readonly Action _ifUnmodifiedSincePreconditionFailed;
- private static readonly Action _ifRangeLastModifiedPreconditionFailed;
- private static readonly Action _ifRangeETagPreconditionFailed;
- private static readonly Action _transformingClientError;
-
- static MvcCoreLoggerExtensions()
- {
- LogDefineOptions SkipEnabledCheckLogOptions = new() { SkipEnabledCheck = true };
- _controllerFactoryExecuting = LoggerMessage.Define(
- LogLevel.Debug,
- new EventId(1, "ControllerFactoryExecuting"),
- "Executing controller factory for controller {Controller} ({AssemblyName})",
- SkipEnabledCheckLogOptions);
-
- _controllerFactoryExecuted = LoggerMessage.Define(
- LogLevel.Debug,
- new EventId(2, "ControllerFactoryExecuted"),
- "Executed controller factory for controller {Controller} ({AssemblyName})",
- SkipEnabledCheckLogOptions);
-
- _actionExecuting = LoggerMessage.Define(
- LogLevel.Information,
- new EventId(1, "ActionExecuting"),
- "Route matched with {RouteData}. Executing action {ActionName}",
- SkipEnabledCheckLogOptions);
-
- _controllerActionExecuting = LoggerMessage.Define(
- LogLevel.Information,
- new EventId(3, "ControllerActionExecuting"),
- "Route matched with {RouteData}. Executing controller action with signature {MethodInfo} on controller {Controller} ({AssemblyName}).",
- SkipEnabledCheckLogOptions);
-
- _actionExecuted = LoggerMessage.Define(
- LogLevel.Information,
- new EventId(2, "ActionExecuted"),
- "Executed action {ActionName} in {ElapsedMilliseconds}ms",
- SkipEnabledCheckLogOptions);
-
- _pageExecuting = LoggerMessage.Define(
- LogLevel.Information,
- new EventId(3, "PageExecuting"),
- "Route matched with {RouteData}. Executing page {PageName}",
- SkipEnabledCheckLogOptions);
-
- _pageExecuted = LoggerMessage.Define(
- LogLevel.Information,
- new EventId(4, "PageExecuted"),
- "Executed page {PageName} in {ElapsedMilliseconds}ms",
- SkipEnabledCheckLogOptions);
-
- _challengeResultExecuting = LoggerMessage.Define(
- LogLevel.Information,
- new EventId(1, "ChallengeResultExecuting"),
- "Executing ChallengeResult with authentication schemes ({Schemes}).",
- SkipEnabledCheckLogOptions);
- _actionMethodExecuting = LoggerMessage.Define(
- LogLevel.Information,
- new EventId(1, "ActionMethodExecuting"),
- "Executing action method {ActionName} - Validation state: {ValidationState}",
- SkipEnabledCheckLogOptions);
-
- _actionMethodExecutingWithArguments = LoggerMessage.Define(
- LogLevel.Trace,
- new EventId(1, "ActionMethodExecutingWithArguments"),
- "Executing action method {ActionName} with arguments ({Arguments})",
- SkipEnabledCheckLogOptions);
-
- _actionMethodExecuted = LoggerMessage.Define(
- LogLevel.Information,
- new EventId(2, "ActionMethodExecuted"),
- "Executed action method {ActionName}, returned result {ActionResult} in {ElapsedMilliseconds}ms.",
- SkipEnabledCheckLogOptions);
-
- _logFilterExecutionPlan = LoggerMessage.Define(
- LogLevel.Debug,
- new EventId(1, "FilterExecutionPlan"),
- "Execution plan of {FilterType} filters (in the following order): {Filters}",
- SkipEnabledCheckLogOptions);
-
- _beforeExecutingMethodOnFilter = LoggerMessage.Define(
- LogLevel.Trace,
- new EventId(2, "BeforeExecutingMethodOnFilter"),
- "{FilterType}: Before executing {Method} on filter {Filter}.");
-
- _afterExecutingMethodOnFilter = LoggerMessage.Define(
- LogLevel.Trace,
- new EventId(3, "AfterExecutingMethodOnFilter"),
- "{FilterType}: After executing {Method} on filter {Filter}.");
- _executingFileResult = LoggerMessage.Define(
- LogLevel.Information,
- new EventId(1, "ExecutingFileResult"),
- "Executing {FileResultType}, sending file '{FileDownloadPath}' with download name '{FileDownloadName}' ...",
- SkipEnabledCheckLogOptions);
-
- _executingFileResultWithNoFileName = LoggerMessage.Define(
- LogLevel.Information,
- new EventId(2, "ExecutingFileResultWithNoFileName"),
- "Executing {FileResultType}, sending file with download name '{FileDownloadName}' ...",
- SkipEnabledCheckLogOptions);
- _resultFilterShortCircuit = LoggerMessage.Define