diff --git a/src/Mvc/Mvc.Core/src/Filters/DisableRequestSizeLimitFilter.cs b/src/Mvc/Mvc.Core/src/Filters/DisableRequestSizeLimitFilter.cs index 28e3a0585095..236c18821ad1 100644 --- a/src/Mvc/Mvc.Core/src/Filters/DisableRequestSizeLimitFilter.cs +++ b/src/Mvc/Mvc.Core/src/Filters/DisableRequestSizeLimitFilter.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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.Http.Features; @@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Mvc.Filters; /// A filter that sets /// to null. /// -internal class DisableRequestSizeLimitFilter : IAuthorizationFilter, IRequestSizePolicy +internal partial class DisableRequestSizeLimitFilter : IAuthorizationFilter, IRequestSizePolicy { private readonly ILogger _logger; @@ -39,7 +39,7 @@ public void OnAuthorization(AuthorizationFilterContext context) var effectivePolicy = context.FindEffectivePolicy(); if (effectivePolicy != null && effectivePolicy != this) { - _logger.NotMostEffectiveFilter(GetType(), effectivePolicy.GetType(), typeof(IRequestSizePolicy)); + Log.NotMostEffectiveFilter(_logger, GetType(), effectivePolicy.GetType(), typeof(IRequestSizePolicy)); return; } @@ -47,16 +47,31 @@ public void OnAuthorization(AuthorizationFilterContext context) if (maxRequestBodySizeFeature == null) { - _logger.FeatureNotFound(); + Log.FeatureNotFound(_logger); } else if (maxRequestBodySizeFeature.IsReadOnly) { - _logger.FeatureIsReadOnly(); + Log.FeatureIsReadOnly(_logger); } else { maxRequestBodySizeFeature.MaxRequestBodySize = null; - _logger.RequestBodySizeLimitDisabled(); + Log.RequestBodySizeLimitDisabled(_logger); } } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Warning, "A request body size limit could not be applied. This server does not support the IHttpRequestBodySizeFeature.", EventName = "FeatureNotFound")] + public static partial void FeatureNotFound(ILogger logger); + + [LoggerMessage(2, LogLevel.Warning, "A request body size limit could not be applied. The IHttpRequestBodySizeFeature for the server is read-only.", EventName = "FeatureIsReadOnly")] + public static partial void FeatureIsReadOnly(ILogger logger); + + [LoggerMessage(3, LogLevel.Debug, "The request body size limit has been disabled.", EventName = "RequestBodySizeLimitDisabled")] + public static partial void RequestBodySizeLimitDisabled(ILogger logger); + + [LoggerMessage(4, LogLevel.Debug, "Execution of filter {OverriddenFilter} is preempted by filter {OverridingFilter} which is the most effective filter implementing policy {FilterPolicy}.", EventName = "NotMostEffectiveFilter")] + public static partial void NotMostEffectiveFilter(ILogger logger, Type overriddenFilter, Type overridingFilter, Type filterPolicy); + } } diff --git a/src/Mvc/Mvc.Core/src/Filters/RequestFormLimitsFilter.cs b/src/Mvc/Mvc.Core/src/Filters/RequestFormLimitsFilter.cs index 503d584238ce..82fce9b7f49e 100644 --- a/src/Mvc/Mvc.Core/src/Filters/RequestFormLimitsFilter.cs +++ b/src/Mvc/Mvc.Core/src/Filters/RequestFormLimitsFilter.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Mvc.Filters; /// /// A filter that configures for the current request. /// -internal class RequestFormLimitsFilter : IAuthorizationFilter, IRequestFormLimitsPolicy +internal partial class RequestFormLimitsFilter : IAuthorizationFilter, IRequestFormLimitsPolicy { private readonly ILogger _logger; @@ -30,7 +30,7 @@ public void OnAuthorization(AuthorizationFilterContext context) var effectivePolicy = context.FindEffectivePolicy(); if (effectivePolicy != null && effectivePolicy != this) { - _logger.NotMostEffectiveFilter(GetType(), effectivePolicy.GetType(), typeof(IRequestFormLimitsPolicy)); + Log.NotMostEffectiveFilter(_logger, GetType(), effectivePolicy.GetType(), typeof(IRequestFormLimitsPolicy)); return; } @@ -41,11 +41,23 @@ public void OnAuthorization(AuthorizationFilterContext context) { // Request form has not been read yet, so set the limits features.Set(new FormFeature(context.HttpContext.Request, FormOptions)); - _logger.AppliedRequestFormLimits(); + Log.AppliedRequestFormLimits(_logger); } else { - _logger.CannotApplyRequestFormLimits(); + Log.CannotApplyRequestFormLimits(_logger); } } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Warning, "Unable to apply configured form options since the request form has already been read.", EventName = "CannotApplyRequestFormLimits")] + public static partial void CannotApplyRequestFormLimits(ILogger logger); + + [LoggerMessage(2, LogLevel.Debug, "Applied the configured form options on the current request.", EventName = "AppliedRequestFormLimits")] + public static partial void AppliedRequestFormLimits(ILogger logger); + + [LoggerMessage(4, LogLevel.Debug, "Execution of filter {OverriddenFilter} is preempted by filter {OverridingFilter} which is the most effective filter implementing policy {FilterPolicy}.", EventName = "NotMostEffectiveFilter")] + public static partial void NotMostEffectiveFilter(ILogger logger, Type overriddenFilter, Type overridingFilter, Type filterPolicy); + } } diff --git a/src/Mvc/Mvc.Core/src/Filters/RequestSizeLimitFilter.cs b/src/Mvc/Mvc.Core/src/Filters/RequestSizeLimitFilter.cs index 64f4a1ec67ff..abb87f9e34b0 100644 --- a/src/Mvc/Mvc.Core/src/Filters/RequestSizeLimitFilter.cs +++ b/src/Mvc/Mvc.Core/src/Filters/RequestSizeLimitFilter.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Filters; /// A filter that sets the /// to the specified . /// -internal class RequestSizeLimitFilter : IAuthorizationFilter, IRequestSizePolicy +internal partial class RequestSizeLimitFilter : IAuthorizationFilter, IRequestSizePolicy { private readonly ILogger _logger; @@ -41,7 +41,7 @@ public void OnAuthorization(AuthorizationFilterContext context) var effectivePolicy = context.FindEffectivePolicy(); if (effectivePolicy != null && effectivePolicy != this) { - _logger.NotMostEffectiveFilter(GetType(), effectivePolicy.GetType(), typeof(IRequestSizePolicy)); + Log.NotMostEffectiveFilter(_logger, GetType(), effectivePolicy.GetType(), typeof(IRequestSizePolicy)); return; } @@ -49,16 +49,31 @@ public void OnAuthorization(AuthorizationFilterContext context) if (maxRequestBodySizeFeature == null) { - _logger.FeatureNotFound(); + Log.FeatureNotFound(_logger); } else if (maxRequestBodySizeFeature.IsReadOnly) { - _logger.FeatureIsReadOnly(); + Log.FeatureIsReadOnly(_logger); } else { maxRequestBodySizeFeature.MaxRequestBodySize = Bytes; - _logger.MaxRequestBodySizeSet(Bytes.ToString(CultureInfo.InvariantCulture)); + Log.MaxRequestBodySizeSet(_logger, Bytes.ToString(CultureInfo.InvariantCulture)); } } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Warning, "A request body size limit could not be applied. This server does not support the IHttpRequestBodySizeFeature.", EventName = "FeatureNotFound")] + public static partial void FeatureNotFound(ILogger logger); + + [LoggerMessage(2, LogLevel.Warning, "A request body size limit could not be applied. The IHttpRequestBodySizeFeature for the server is read-only.", EventName = "FeatureIsReadOnly")] + public static partial void FeatureIsReadOnly(ILogger logger); + + [LoggerMessage(3, LogLevel.Debug, "The maximum request body size has been set to {RequestSize}.", EventName = "MaxRequestBodySizeSet")] + public static partial void MaxRequestBodySizeSet(ILogger logger, string requestSize); + + [LoggerMessage(4, LogLevel.Debug, "Execution of filter {OverriddenFilter} is preempted by filter {OverridingFilter} which is the most effective filter implementing policy {FilterPolicy}.", EventName = "NotMostEffectiveFilter")] + public static partial void NotMostEffectiveFilter(ILogger logger, Type overriddenFilter, Type overridingFilter, Type filterPolicy); + } } diff --git a/src/Mvc/Mvc.Core/src/Filters/ResponseCacheFilter.cs b/src/Mvc/Mvc.Core/src/Filters/ResponseCacheFilter.cs index ee66600683c7..fa892a91756f 100644 --- a/src/Mvc/Mvc.Core/src/Filters/ResponseCacheFilter.cs +++ b/src/Mvc/Mvc.Core/src/Filters/ResponseCacheFilter.cs @@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Mvc.Filters; /// /// An which sets the appropriate headers related to response caching. /// -internal class ResponseCacheFilter : IActionFilter, IResponseCacheFilter +internal partial class ResponseCacheFilter : IActionFilter, IResponseCacheFilter { private readonly ResponseCacheFilterExecutor _executor; private readonly ILogger _logger; @@ -91,7 +91,7 @@ public void OnActionExecuting(ActionExecutingContext context) var effectivePolicy = context.FindEffectivePolicy(); if (effectivePolicy != null && effectivePolicy != this) { - _logger.NotMostEffectiveFilter(GetType(), effectivePolicy.GetType(), typeof(IResponseCacheFilter)); + Log.NotMostEffectiveFilter(_logger, GetType(), effectivePolicy.GetType(), typeof(IResponseCacheFilter)); return; } @@ -102,4 +102,10 @@ public void OnActionExecuting(ActionExecutingContext context) public void OnActionExecuted(ActionExecutedContext context) { } + + private static partial class Log + { + [LoggerMessage(4, LogLevel.Debug, "Execution of filter {OverriddenFilter} is preempted by filter {OverridingFilter} which is the most effective filter implementing policy {FilterPolicy}.", EventName = "NotMostEffectiveFilter")] + public static partial void NotMostEffectiveFilter(ILogger logger, Type overriddenFilter, Type overridingFilter, Type filterPolicy); + } } diff --git a/src/Mvc/Mvc.Core/src/Formatters/FormatFilter.cs b/src/Mvc/Mvc.Core/src/Formatters/FormatFilter.cs index f734745cb9b0..d0b74ccdc9f1 100644 --- a/src/Mvc/Mvc.Core/src/Formatters/FormatFilter.cs +++ b/src/Mvc/Mvc.Core/src/Formatters/FormatFilter.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters; /// A filter that will use the format value in the route data or query string to set the content type on an /// returned from an action. /// -public class FormatFilter : IFormatFilter, IResourceFilter, IResultFilter +public partial class FormatFilter : IFormatFilter, IResourceFilter, IResultFilter { private readonly MvcOptions _options; private readonly ILogger _logger; @@ -82,7 +82,7 @@ public void OnResourceExecuting(ResourceExecutingContext context) var contentType = _options.FormatterMappings.GetMediaTypeMappingForFormat(format); if (contentType == null) { - _logger.UnsupportedFormatFilterContentType(format); + Log.UnsupportedFormatFilterContentType(_logger, format); // no contentType exists for the format, return 404 context.Result = new NotFoundResult(); @@ -100,7 +100,7 @@ public void OnResourceExecuting(ResourceExecutingContext context) // Check if support is adequate for requested media type. if (supportedMediaTypes.Count == 0) { - _logger.ActionDoesNotExplicitlySpecifyContentTypes(); + Log.ActionDoesNotExplicitlySpecifyContentTypes(_logger); return; } @@ -163,7 +163,7 @@ public void OnResultExecuting(ResultExecutingContext context) if (objectResult.ContentTypes.Count == 1 || !string.IsNullOrEmpty(context.HttpContext.Response.ContentType)) { - _logger.CannotApplyFormatFilterContentType(format); + Log.CannotApplyFormatFilterContentType(_logger, format); return; } @@ -179,4 +179,16 @@ public void OnResultExecuting(ResultExecutingContext context) public void OnResultExecuted(ResultExecutedContext context) { } + + 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(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); + + [LoggerMessage(5, LogLevel.Debug, "Current action does not explicitly specify any content types for the response.", EventName = "ActionDoesNotExplicitlySpecifyContentTypes")] + public static partial void ActionDoesNotExplicitlySpecifyContentTypes(ILogger logger); + } } diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/ActionSelector.cs b/src/Mvc/Mvc.Core/src/Infrastructure/ActionSelector.cs index d06276cb2b60..002003c5d147 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/ActionSelector.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/ActionSelector.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure; /// /// A default implementation. /// -internal class ActionSelector : IActionSelector +internal partial class ActionSelector : IActionSelector { private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider; private readonly ActionConstraintCache _actionConstraintCache; @@ -108,8 +108,7 @@ public IReadOnlyList SelectCandidates(RouteContext context) var actionNames = string.Join( Environment.NewLine, finalMatches.Select(a => a.DisplayName)); - - _logger.AmbiguousActions(actionNames); + Log.AmbiguousActions(_logger, actionNames); var message = Resources.FormatDefaultActionSelector_AmbiguousActions( Environment.NewLine, @@ -216,7 +215,8 @@ public IReadOnlyList SelectCandidates(RouteContext context) if (!constraint.Accept(constraintContext)) { isMatch = false; - _logger.ConstraintMismatch( + Log.ConstraintMismatch( + _logger, candidate.Action.DisplayName, candidate.Action.Id, constraint); @@ -256,4 +256,13 @@ public IReadOnlyList SelectCandidates(RouteContext context) return EvaluateActionConstraintsCore(context, actionsWithoutConstraint, order); } } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Error, "Request matched multiple actions resulting in ambiguity. Matching actions: {AmbiguousActions}", EventName = "AmbiguousActions")] + public static partial void AmbiguousActions(ILogger logger, string ambiguousActions); + + [LoggerMessage(2, LogLevel.Debug, "Action '{ActionName}' with id '{ActionId}' did not match the constraint '{ActionConstraint}'", EventName = "ConstraintMismatch")] + public static partial void ConstraintMismatch(ILogger logger, string? actionName, string actionId, IActionConstraint actionConstraint); + } } diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/ContentResultExecutor.cs b/src/Mvc/Mvc.Core/src/Infrastructure/ContentResultExecutor.cs index ae405d89db5a..5529cd232eb6 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/ContentResultExecutor.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/ContentResultExecutor.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure; /// /// A that is responsible for /// -public class ContentResultExecutor : IActionResultExecutor +public partial class ContentResultExecutor : IActionResultExecutor { private const string DefaultContentType = "text/plain; charset=utf-8"; private readonly ILogger _logger; @@ -60,7 +60,7 @@ public virtual async Task ExecuteAsync(ActionContext context, ContentResult resu response.StatusCode = result.StatusCode.Value; } - _logger.ContentResultExecuting(resolvedContentType); + Log.ContentResultExecuting(_logger, resolvedContentType); if (result.Content != null) { @@ -78,4 +78,10 @@ public virtual async Task ExecuteAsync(ActionContext context, ContentResult resu } } } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Information, "Executing ContentResult with HTTP Response ContentType of {ContentType}", EventName = "ContentResultExecuting")] + public static partial void ContentResultExecuting(ILogger logger, string contentType); + } } diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/DefaultOutputFormatterSelector.cs b/src/Mvc/Mvc.Core/src/Infrastructure/DefaultOutputFormatterSelector.cs index 8377bb053081..fa3e1442d15c 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/DefaultOutputFormatterSelector.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/DefaultOutputFormatterSelector.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure; /// /// The default implementation of . /// -public class DefaultOutputFormatterSelector : OutputFormatterSelector +public partial class DefaultOutputFormatterSelector : OutputFormatterSelector { private static readonly Comparison _sortFunction = (left, right) => { @@ -84,7 +84,7 @@ public DefaultOutputFormatterSelector(IOptions options, ILoggerFacto } } - _logger.RegisteredOutputFormatters(formatters); + Log.RegisteredOutputFormatters(_logger, formatters); var request = context.HttpContext.Request; var acceptableMediaTypes = GetAcceptableMediaTypes(request); @@ -95,7 +95,7 @@ public DefaultOutputFormatterSelector(IOptions options, ILoggerFacto { // There is either no Accept header value, or it contained */* and we // are not currently respecting the 'browser accept header'. - _logger.NoAcceptForNegotiation(); + Log.NoAcceptForNegotiation(_logger); selectFormatterWithoutRegardingAcceptHeader = true; } @@ -103,7 +103,7 @@ public DefaultOutputFormatterSelector(IOptions options, ILoggerFacto { if (contentTypes.Count == 0) { - _logger.SelectingOutputFormatterUsingAcceptHeader(acceptableMediaTypes); + Log.SelectingOutputFormatterUsingAcceptHeader(_logger, acceptableMediaTypes); // Use whatever formatter can meet the client's request selectedFormatter = SelectFormatterUsingSortedAcceptHeaders( @@ -113,7 +113,7 @@ public DefaultOutputFormatterSelector(IOptions options, ILoggerFacto } else { - _logger.SelectingOutputFormatterUsingAcceptHeaderAndExplicitContentTypes(acceptableMediaTypes, contentTypes); + Log.SelectingOutputFormatterUsingAcceptHeaderAndExplicitContentTypes(_logger, acceptableMediaTypes, contentTypes); // Verify that a content type from the context is compatible with the client's request selectedFormatter = SelectFormatterUsingSortedAcceptHeadersAndContentTypes( @@ -125,7 +125,7 @@ public DefaultOutputFormatterSelector(IOptions options, ILoggerFacto if (selectedFormatter == null) { - _logger.NoFormatterFromNegotiation(acceptableMediaTypes); + Log.NoFormatterFromNegotiation(_logger, acceptableMediaTypes); if (!_returnHttpNotAcceptable) { @@ -138,7 +138,7 @@ public DefaultOutputFormatterSelector(IOptions options, ILoggerFacto { if (contentTypes.Count == 0) { - _logger.SelectingOutputFormatterWithoutUsingContentTypes(); + Log.SelectingOutputFormatterWithoutUsingContentTypes(_logger); selectedFormatter = SelectFormatterNotUsingContentType( context, @@ -146,7 +146,7 @@ public DefaultOutputFormatterSelector(IOptions options, ILoggerFacto } else { - _logger.SelectingOutputFormatterUsingContentTypes(contentTypes); + Log.SelectingOutputFormatterUsingContentTypes(_logger, contentTypes); selectedFormatter = SelectFormatterUsingAnyAcceptableContentType( context, @@ -186,7 +186,7 @@ private List GetAcceptableMediaTypes(HttpRequest re OutputFormatterCanWriteContext formatterContext, IList formatters) { - _logger.SelectFirstCanWriteFormatter(); + Log.SelectFirstCanWriteFormatter(_logger); foreach (var formatter in formatters) { @@ -296,4 +296,31 @@ private static void ValidateContentTypes(MediaTypeCollection contentTypes) } } } + + private static partial class Log + { + [LoggerMessage(4, LogLevel.Debug, "No information found on request to perform content negotiation.", EventName = "NoAcceptForNegotiation")] + public static partial void NoAcceptForNegotiation(ILogger logger); + + [LoggerMessage(5, LogLevel.Debug, "Could not find an output formatter based on content negotiation. Accepted types were ({AcceptTypes})", EventName = "NoFormatterFromNegotiation")] + public static partial void NoFormatterFromNegotiation(ILogger logger, IList acceptTypes); + + [LoggerMessage(6, LogLevel.Debug, "Attempting to select an output formatter based on Accept header '{AcceptHeader}'.", EventName = "SelectingOutputFormatterUsingAcceptHeader")] + public static partial void SelectingOutputFormatterUsingAcceptHeader(ILogger logger, IEnumerable acceptHeader); + + [LoggerMessage(7, LogLevel.Debug, "Attempting to select an output formatter based on Accept header '{AcceptHeader}' and explicitly specified content types '{ExplicitContentTypes}'. The content types in the accept header must be a subset of the explicitly set content types.", EventName = "SelectingOutputFormatterUsingAcceptHeaderAndExplicitContentTypes")] + public static partial void SelectingOutputFormatterUsingAcceptHeaderAndExplicitContentTypes(ILogger logger, IEnumerable acceptHeader, MediaTypeCollection explicitContentTypes); + + [LoggerMessage(8, LogLevel.Debug, "Attempting to select an output formatter without using a content type as no explicit content types were specified for the response.", EventName = "SelectingOutputFormatterWithoutUsingContentTypes")] + public static partial void SelectingOutputFormatterWithoutUsingContentTypes(ILogger logger); + + [LoggerMessage(9, LogLevel.Debug, "Attempting to select the first output formatter in the output formatters list which supports a content type from the explicitly specified content types '{ExplicitContentTypes}'.", EventName = "SelectingOutputFormatterUsingContentTypes")] + public static partial void SelectingOutputFormatterUsingContentTypes(ILogger logger, MediaTypeCollection explicitContentTypes); + + [LoggerMessage(10, LogLevel.Debug, "Attempting to select the first formatter in the output formatters list which can write the result.", EventName = "SelectingFirstCanWriteFormatter")] + public static partial void SelectFirstCanWriteFormatter(ILogger logger); + + [LoggerMessage(11, LogLevel.Debug, "List of registered output formatters, in the following order: {OutputFormatters}", EventName = "RegisteredOutputFormatters")] + public static partial void RegisteredOutputFormatters(ILogger logger, IEnumerable outputFormatters); + } } diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/FileContentResultExecutor.cs b/src/Mvc/Mvc.Core/src/Infrastructure/FileContentResultExecutor.cs index 80cd5a124610..5449a4d98697 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/FileContentResultExecutor.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/FileContentResultExecutor.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure; /// /// A /// -public class FileContentResultExecutor : FileResultExecutorBase, IActionResultExecutor +public partial class FileContentResultExecutor : FileResultExecutorBase, IActionResultExecutor { /// /// Intializes a new . @@ -79,10 +79,16 @@ protected virtual Task WriteFileAsync(ActionContext context, FileContentResult r if (range != null) { - Logger.WritingRangeToBody(); + Log.WritingRangeToBody(Logger); } var fileContentStream = new MemoryStream(result.FileContents); return WriteFileAsync(context.HttpContext, fileContentStream, range, rangeLength); } + + private static partial class Log + { + [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 3a4d3461a661..51b88f7f223b 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/FileStreamResultExecutor.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/FileStreamResultExecutor.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure; /// /// An for a file stream result. /// -public class FileStreamResultExecutor : FileResultExecutorBase, IActionResultExecutor +public partial class FileStreamResultExecutor : FileResultExecutorBase, IActionResultExecutor { /// /// Initializes a new . @@ -92,9 +92,15 @@ protected virtual Task WriteFileAsync( if (range != null) { - Logger.WritingRangeToBody(); + Log.WritingRangeToBody(Logger); } return WriteFileAsync(context.HttpContext, result.FileStream, range, rangeLength); } + + private static partial class Log + { + [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/LocalRedirectResultExecutor.cs b/src/Mvc/Mvc.Core/src/Infrastructure/LocalRedirectResultExecutor.cs index 8b989406c8ea..51d386c6ef5f 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/LocalRedirectResultExecutor.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/LocalRedirectResultExecutor.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure; /// /// A that handles . /// -public class LocalRedirectResultExecutor : IActionResultExecutor +public partial class LocalRedirectResultExecutor : IActionResultExecutor { private readonly ILogger _logger; private readonly IUrlHelperFactory _urlHelperFactory; @@ -61,7 +61,7 @@ public virtual Task ExecuteAsync(ActionContext context, LocalRedirectResult resu } var destinationUrl = urlHelper.Content(result.Url); - _logger.LocalRedirectResultExecuting(destinationUrl); + Log.LocalRedirectResultExecuting(_logger, destinationUrl); if (result.PreserveMethod) { @@ -76,4 +76,10 @@ public virtual Task ExecuteAsync(ActionContext context, LocalRedirectResult resu return Task.CompletedTask; } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Information, "Executing LocalRedirectResult, redirecting to {Destination}.", EventName = "LocalRedirectResultExecuting")] + public static partial void LocalRedirectResultExecuting(ILogger logger, string destination); + } } diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/PhysicalFileResultExecutor.cs b/src/Mvc/Mvc.Core/src/Infrastructure/PhysicalFileResultExecutor.cs index ba8378dc3277..e377cb86f3dd 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/PhysicalFileResultExecutor.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/PhysicalFileResultExecutor.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure; /// /// A for . /// -public class PhysicalFileResultExecutor : FileResultExecutorBase, IActionResultExecutor +public partial class PhysicalFileResultExecutor : FileResultExecutorBase, IActionResultExecutor { /// /// Initializes a new instance of . @@ -97,7 +97,7 @@ internal static Task WriteFileAsyncInternal( if (range != null) { - logger.WritingRangeToBody(); + Log.WritingRangeToBody(logger); } if (range != null) @@ -177,4 +177,10 @@ protected class FileMetadata /// public DateTimeOffset LastModified { get; set; } } + + private static partial class Log + { + [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/RedirectResultExecutor.cs b/src/Mvc/Mvc.Core/src/Infrastructure/RedirectResultExecutor.cs index 997c1ea38b08..5cf974f9cc33 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/RedirectResultExecutor.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/RedirectResultExecutor.cs @@ -1,7 +1,6 @@ // 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.Http; using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.Extensions.Logging; @@ -11,7 +10,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure; /// /// A for . /// -public class RedirectResultExecutor : IActionResultExecutor +public partial class RedirectResultExecutor : IActionResultExecutor { private readonly ILogger _logger; private readonly IUrlHelperFactory _urlHelperFactory; @@ -59,7 +58,7 @@ public virtual Task ExecuteAsync(ActionContext context, RedirectResult result) destinationUrl = urlHelper.Content(result.Url); } - _logger.RedirectResultExecuting(destinationUrl); + Log.RedirectResultExecuting(_logger, destinationUrl); if (result.PreserveMethod) { @@ -74,4 +73,10 @@ public virtual Task ExecuteAsync(ActionContext context, RedirectResult result) return Task.CompletedTask; } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Information, "Executing RedirectResult, redirecting to {Destination}.", EventName = "RedirectResultExecuting")] + public static partial void RedirectResultExecuting(ILogger logger, string destination); + } } diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/RedirectToActionResultExecutor.cs b/src/Mvc/Mvc.Core/src/Infrastructure/RedirectToActionResultExecutor.cs index e16011a1680e..c32f97d18b89 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/RedirectToActionResultExecutor.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/RedirectToActionResultExecutor.cs @@ -1,7 +1,6 @@ // 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.Http; using Microsoft.AspNetCore.Mvc.Core; using Microsoft.AspNetCore.Mvc.Routing; @@ -12,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure; /// /// A for . /// -public class RedirectToActionResultExecutor : IActionResultExecutor +public partial class RedirectToActionResultExecutor : IActionResultExecutor { private readonly ILogger _logger; private readonly IUrlHelperFactory _urlHelperFactory; @@ -65,7 +64,7 @@ public virtual Task ExecuteAsync(ActionContext context, RedirectToActionResult r throw new InvalidOperationException(Resources.NoRoutesMatched); } - _logger.RedirectToActionResultExecuting(destinationUrl); + Log.RedirectToActionResultExecuting(_logger, destinationUrl); if (result.PreserveMethod) { @@ -80,4 +79,10 @@ public virtual Task ExecuteAsync(ActionContext context, RedirectToActionResult r return Task.CompletedTask; } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Information, "Executing RedirectResult, redirecting to {Destination}.", EventName = "RedirectToActionResultExecuting")] + public static partial void RedirectToActionResultExecuting(ILogger logger, string destination); + } } diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/RedirectToPageResultExecutor.cs b/src/Mvc/Mvc.Core/src/Infrastructure/RedirectToPageResultExecutor.cs index 4fd7f89570ef..e90904d8b348 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/RedirectToPageResultExecutor.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/RedirectToPageResultExecutor.cs @@ -1,7 +1,6 @@ // 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.Http; using Microsoft.AspNetCore.Mvc.Core; using Microsoft.AspNetCore.Mvc.Routing; @@ -12,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure; /// /// A for . /// -public class RedirectToPageResultExecutor : IActionResultExecutor +public partial class RedirectToPageResultExecutor : IActionResultExecutor { private readonly ILogger _logger; private readonly IUrlHelperFactory _urlHelperFactory; @@ -65,7 +64,7 @@ public virtual Task ExecuteAsync(ActionContext context, RedirectToPageResult res throw new InvalidOperationException(Resources.FormatNoRoutesMatchedForPage(result.PageName)); } - _logger.RedirectToPageResultExecuting(result.PageName); + Log.RedirectToPageResultExecuting(_logger, result.PageName); if (result.PreserveMethod) { @@ -80,4 +79,10 @@ public virtual Task ExecuteAsync(ActionContext context, RedirectToPageResult res return Task.CompletedTask; } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Information, "Executing RedirectToPageResult, redirecting to {Page}.", EventName = "RedirectToPageResultExecuting")] + public static partial void RedirectToPageResultExecuting(ILogger logger, string? page); + } } diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/RedirectToRouteResultExecutor.cs b/src/Mvc/Mvc.Core/src/Infrastructure/RedirectToRouteResultExecutor.cs index e21e0144462f..7ce084d57e4b 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/RedirectToRouteResultExecutor.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/RedirectToRouteResultExecutor.cs @@ -1,7 +1,6 @@ // 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.Http; using Microsoft.AspNetCore.Mvc.Core; using Microsoft.AspNetCore.Mvc.Routing; @@ -12,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure; /// /// A for . /// -public class RedirectToRouteResultExecutor : IActionResultExecutor +public partial class RedirectToRouteResultExecutor : IActionResultExecutor { private readonly ILogger _logger; private readonly IUrlHelperFactory _urlHelperFactory; @@ -54,7 +53,7 @@ public virtual Task ExecuteAsync(ActionContext context, RedirectToRouteResult re throw new InvalidOperationException(Resources.NoRoutesMatched); } - _logger.RedirectToRouteResultExecuting(destinationUrl, result.RouteName); + Log.RedirectToRouteResultExecuting(_logger, destinationUrl, result.RouteName); if (result.PreserveMethod) { @@ -69,4 +68,10 @@ public virtual Task ExecuteAsync(ActionContext context, RedirectToRouteResult re return Task.CompletedTask; } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Information, "Executing RedirectToRouteResult, redirecting to {Destination} from route {RouteName}.", EventName = "RedirectToRouteResultExecuting")] + public static partial void RedirectToRouteResultExecuting(ILogger logger, string destination, string? routeName); + } } diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/ResourceInvoker.cs b/src/Mvc/Mvc.Core/src/Infrastructure/ResourceInvoker.cs index f0c437bd3079..ae30ee19f9b4 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/ResourceInvoker.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/ResourceInvoker.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure; -internal abstract class ResourceInvoker +internal abstract partial class ResourceInvoker { protected readonly DiagnosticListener _diagnosticListener; protected readonly ILogger _logger; @@ -272,7 +272,7 @@ static async Task Logged(ResourceInvoker invoker, IActionResult result) var actionContext = invoker._actionContext; invoker._diagnosticListener.BeforeActionResult(actionContext, result); - invoker._logger.BeforeExecutingActionResult(result); + Log.BeforeExecutingActionResult(invoker._logger, result); try { @@ -281,7 +281,7 @@ static async Task Logged(ResourceInvoker invoker, IActionResult result) finally { invoker._diagnosticListener.AfterActionResult(actionContext, result); - invoker._logger.AfterExecutingActionResult(result); + Log.AfterExecutingActionResult(invoker._logger, result); } } } @@ -411,8 +411,7 @@ private Task Next(ref State next, ref Scope scope, ref object? state, ref bool i Debug.Assert(state != null); Debug.Assert(_authorizationContext != null); Debug.Assert(_authorizationContext.Result != null); - - _logger.AuthorizationFailure((IFilterMetadata)state); + Log.AuthorizationFailure(_logger, (IFilterMetadata)state); // This is a short-circuit - execute relevant result filters + result and complete this invocation. isCompleted = true; @@ -596,8 +595,7 @@ private Task Next(ref State next, ref Scope scope, ref object? state, ref bool i Debug.Assert(state != null); Debug.Assert(_resourceExecutingContext != null); Debug.Assert(_resourceExecutedContext != null); - - _logger.ResourceFilterShortCircuited((IFilterMetadata)state); + Log.ResourceFilterShortCircuited(_logger, (IFilterMetadata)state); _result = _resourceExecutingContext.Result; var task = InvokeAlwaysRunResultFilters(); @@ -1605,4 +1603,29 @@ 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 89d6a17c7439..59c8a0976943 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/VirtualFileResultExecutor.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/VirtualFileResultExecutor.cs @@ -1,7 +1,6 @@ // 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.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Core; @@ -14,7 +13,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure; /// /// A for . /// -public class VirtualFileResultExecutor : FileResultExecutorBase, IActionResultExecutor +public partial class VirtualFileResultExecutor : FileResultExecutorBase, IActionResultExecutor { private readonly IWebHostEnvironment _hostingEnvironment; @@ -105,7 +104,7 @@ internal static Task WriteFileAsyncInternal( if (range != null) { - logger.WritingRangeToBody(); + Log.WritingRangeToBody(logger); } if (range != null) @@ -159,4 +158,10 @@ protected virtual Stream GetFileStream(IFileInfo fileInfo) { return fileInfo.CreateReadStream(); } + + private static partial class Log + { + [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/FormFileModelBinder.cs b/src/Mvc/Mvc.Core/src/ModelBinding/Binders/FormFileModelBinder.cs index 04776ef5da4e..ce6596db8104 100644 --- a/src/Mvc/Mvc.Core/src/ModelBinding/Binders/FormFileModelBinder.cs +++ b/src/Mvc/Mvc.Core/src/ModelBinding/Binders/FormFileModelBinder.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders; /// /// implementation to bind posted files to . /// -public class FormFileModelBinder : IModelBinder +public partial class FormFileModelBinder : IModelBinder { private readonly ILogger _logger; @@ -164,7 +164,7 @@ private async Task GetFormFilesAsync( if (postedFiles.Count == 0) { - _logger.NoFilesFoundInRequest(); + Log.NoFilesFoundInRequest(_logger); } } else @@ -211,4 +211,10 @@ public IReadOnlyList GetFiles(string name) return files; } } + + private static partial class Log + { + [LoggerMessage(21, LogLevel.Debug, "No files found in the request to bind the model to.", EventName = "NoFilesFoundInRequest")] + public static partial void NoFilesFoundInRequest(ILogger logger); + } } diff --git a/src/Mvc/Mvc.Core/src/ModelBinding/Binders/HeaderModelBinderProvider.cs b/src/Mvc/Mvc.Core/src/ModelBinding/Binders/HeaderModelBinderProvider.cs index 724efb810538..fd29db9b64c4 100644 --- a/src/Mvc/Mvc.Core/src/ModelBinding/Binders/HeaderModelBinderProvider.cs +++ b/src/Mvc/Mvc.Core/src/ModelBinding/Binders/HeaderModelBinderProvider.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders; /// /// An for binding header values. /// -public class HeaderModelBinderProvider : IModelBinderProvider +public partial class HeaderModelBinderProvider : IModelBinderProvider { /// public IModelBinder? GetBinder(ModelBinderProviderContext context) @@ -34,7 +34,7 @@ public class HeaderModelBinderProvider : IModelBinderProvider if (!IsSimpleType(modelMetadata)) { - logger.CannotCreateHeaderModelBinder(modelMetadata.ModelType); + Log.CannotCreateHeaderModelBinder(logger, modelMetadata.ModelType); return null; } @@ -64,4 +64,10 @@ private static bool IsSimpleType(ModelMetadata modelMetadata) var metadata = modelMetadata.ElementMetadata ?? modelMetadata; return !metadata.IsComplexType; } + + private static partial class Log + { + [LoggerMessage(20, LogLevel.Debug, "Could not create a binder for type '{ModelType}' as this binder only supports simple types (like string, int, bool, enum) or a collection of simple types.", EventName = "CannotCreateHeaderModelBinder")] + public static partial void CannotCreateHeaderModelBinder(ILogger logger, Type modelType); + } } diff --git a/src/Mvc/Mvc.Core/src/ModelBinding/ModelBinderFactory.cs b/src/Mvc/Mvc.Core/src/ModelBinding/ModelBinderFactory.cs index 3a96afac1417..30754d9dcff4 100644 --- a/src/Mvc/Mvc.Core/src/ModelBinding/ModelBinderFactory.cs +++ b/src/Mvc/Mvc.Core/src/ModelBinding/ModelBinderFactory.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding; /// /// A factory for instances. /// -public class ModelBinderFactory : IModelBinderFactory +public partial class ModelBinderFactory : IModelBinderFactory { private readonly IModelMetadataProvider _metadataProvider; private readonly IModelBinderProvider[] _providers; @@ -44,7 +44,7 @@ public ModelBinderFactory( var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - logger.RegisteredModelBinderProviders(_providers); + Log.RegisteredModelBinderProviders(logger, _providers); } /// @@ -329,4 +329,10 @@ public override string ToString() } } } + + private static partial class Log + { + [LoggerMessage(12, LogLevel.Debug, "Registered model binder providers, in the following order: {ModelBinderProviders}", EventName = "RegisteredModelBinderProviders")] + public static partial void RegisteredModelBinderProviders(ILogger logger, IModelBinderProvider[] modelBinderProviders); + } } diff --git a/src/Mvc/Mvc.Core/src/MvcCoreLoggerExtensions.cs b/src/Mvc/Mvc.Core/src/MvcCoreLoggerExtensions.cs index 53ecf1a827f7..7fdff5b34705 100644 --- a/src/Mvc/Mvc.Core/src/MvcCoreLoggerExtensions.cs +++ b/src/Mvc/Mvc.Core/src/MvcCoreLoggerExtensions.cs @@ -7,10 +7,8 @@ using System.Globalization; using System.Linq; using System.Reflection; -using System.Security.Claims; using System.Text; using Microsoft.AspNetCore.Mvc.Abstractions; -using Microsoft.AspNetCore.Mvc.ActionConstraints; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Filters; @@ -39,9 +37,6 @@ internal static partial class MvcCoreLoggerExtensions private static readonly Action _pageExecuted; private static readonly Action _challengeResultExecuting; - - private static readonly Action _contentResultExecuting; - private static readonly Action _actionMethodExecuting; private static readonly Action _actionMethodExecutingWithArguments; private static readonly Action _actionMethodExecuted; @@ -49,64 +44,25 @@ internal static partial class MvcCoreLoggerExtensions private static readonly Action _logFilterExecutionPlan; private static readonly Action _beforeExecutingMethodOnFilter; private static readonly Action _afterExecutingMethodOnFilter; - private static readonly Action _beforeExecutingActionResult; - private static readonly Action _afterExecutingActionResult; - - private static readonly Action _ambiguousActions; - private static readonly Action _constraintMismatch; - private static readonly Action _executingFileResult; private static readonly Action _executingFileResultWithNoFileName; - private static readonly Action _notEnabledForRangeProcessing; - private static readonly Action _writingRangeToBody; - private static readonly Action _authorizationFailure; - private static readonly Action _resourceFilterShortCircuit; private static readonly Action _resultFilterShortCircuit; private static readonly Action _actionFilterShortCircuit; private static readonly Action _exceptionFilterShortCircuit; private static readonly Action _forbidResultExecuting; - private static readonly Action _signInResultExecuting; private static readonly Action _signOutResultExecuting; - - private static readonly Action _httpStatusCodeResultExecuting; - - private static readonly Action _localRedirectResultExecuting; - private static readonly Action _objectResultExecuting; private static readonly Action, Exception> _noFormatter; private static readonly Action _formatterSelected; - private static readonly Action _skippedContentNegotiation; - private static readonly Action _noAcceptForNegotiation; - private static readonly Action, Exception> _noFormatterFromNegotiation; - private static readonly Action _inputFormatterSelected; private static readonly Action _inputFormatterRejected; private static readonly Action _noInputFormatterSelected; private static readonly Action _removeFromBodyAttribute; - - private static readonly Action _redirectResultExecuting; - - private static readonly Action _redirectToActionResultExecuting; - - private static readonly Action _redirectToRouteResultExecuting; - private static readonly Action _noActionsMatched; - - private static readonly Action _redirectToPageResultExecuting; - - private static readonly Action _featureNotFound; - private static readonly Action _featureIsReadOnly; - private static readonly Action _maxRequestBodySizeSet; - private static readonly Action _requestBodySizeLimitDisabled; - - private static readonly Action _cannotApplyRequestFormLimits; - private static readonly Action _appliedRequestFormLimits; - private static readonly Action _modelStateInvalidFilterExecuting; private static readonly Action _inferredParameterSource; - private static readonly Action _registeredModelBinderProviders; private static readonly Action _foundNoValueForPropertyInRequest; private static readonly Action _foundNoValueForParameterInRequest; private static readonly Action _foundNoValueInRequest; @@ -115,9 +71,7 @@ internal static partial class MvcCoreLoggerExtensions private static readonly Action _noPublicSettableProperties; private static readonly Action _cannotBindToComplexType; private static readonly Action _cannotBindToFilesCollectionDueToUnsupportedContentType; - private static readonly Action _cannotCreateHeaderModelBinder; private static readonly Action _cannotCreateHeaderModelBinderCompatVersion_2_0; - private static readonly Action _noFilesFoundInRequest; private static readonly Action _noNonIndexBasedFormatFoundForCollection; private static readonly Action _attemptingToBindCollectionUsingIndices; private static readonly Action _attemptingToBindCollectionOfKeyValuePair; @@ -136,22 +90,10 @@ internal static partial class MvcCoreLoggerExtensions private static readonly Action _doneAttemptingToValidateProperty; private static readonly Action _attemptingToValidateParameter; private static readonly Action _doneAttemptingToValidateParameter; - private static readonly Action _unsupportedFormatFilterContentType; private static readonly Action _actionDoesNotSupportFormatFilterContentType; - private static readonly Action _cannotApplyFormatFilterContentType; - private static readonly Action _actionDoesNotExplicitlySpecifyContentTypes; - private static readonly Action, Exception> _selectingOutputFormatterUsingAcceptHeader; - private static readonly Action _ifMatchPreconditionFailed; private static readonly Action _ifUnmodifiedSincePreconditionFailed; private static readonly Action _ifRangeLastModifiedPreconditionFailed; private static readonly Action _ifRangeETagPreconditionFailed; - private static readonly Action, MediaTypeCollection, Exception> _selectingOutputFormatterUsingAcceptHeaderAndExplicitContentTypes; - private static readonly Action _selectingOutputFormatterWithoutUsingContentTypes; - private static readonly Action _selectingOutputFormatterUsingContentTypes; - private static readonly Action _selectingFirstCanWriteFormatter; - private static readonly Action _notMostEffectiveFilter; - private static readonly Action, Exception> _registeredOutputFormatters; - private static readonly Action _transformingClientError; static MvcCoreLoggerExtensions() @@ -204,12 +146,6 @@ static MvcCoreLoggerExtensions() new EventId(1, "ChallengeResultExecuting"), "Executing ChallengeResult with authentication schemes ({Schemes}).", SkipEnabledCheckLogOptions); - - _contentResultExecuting = LoggerMessage.Define( - LogLevel.Information, - new EventId(1, "ContentResultExecuting"), - "Executing ContentResult with HTTP Response ContentType of {ContentType}"); - _actionMethodExecuting = LoggerMessage.Define( LogLevel.Information, new EventId(1, "ActionMethodExecuting"), @@ -243,27 +179,6 @@ static MvcCoreLoggerExtensions() LogLevel.Trace, new EventId(3, "AfterExecutingMethodOnFilter"), "{FilterType}: After executing {Method} on filter {Filter}."); - - _beforeExecutingActionResult = LoggerMessage.Define( - LogLevel.Trace, - new EventId(4, "BeforeExecutingActionResult"), - "Before executing action result {ActionResult}."); - - _afterExecutingActionResult = LoggerMessage.Define( - LogLevel.Trace, - new EventId(5, "AfterExecutingActionResult"), - "After executing action result {ActionResult}."); - - _ambiguousActions = LoggerMessage.Define( - LogLevel.Error, - new EventId(1, "AmbiguousActions"), - "Request matched multiple actions resulting in ambiguity. Matching actions: {AmbiguousActions}"); - - _constraintMismatch = LoggerMessage.Define( - LogLevel.Debug, - new EventId(2, "ConstraintMismatch"), - "Action '{ActionName}' with id '{ActionId}' did not match the constraint '{ActionConstraint}'"); - _executingFileResult = LoggerMessage.Define( LogLevel.Information, new EventId(1, "ExecutingFileResult"), @@ -275,17 +190,6 @@ static MvcCoreLoggerExtensions() new EventId(2, "ExecutingFileResultWithNoFileName"), "Executing {FileResultType}, sending file with download name '{FileDownloadName}' ...", SkipEnabledCheckLogOptions); - - _authorizationFailure = LoggerMessage.Define( - LogLevel.Information, - new EventId(3, "AuthorizationFailure"), - "Authorization failed for the request at filter '{AuthorizationFilter}'."); - - _resourceFilterShortCircuit = LoggerMessage.Define( - LogLevel.Debug, - new EventId(4, "ResourceFilterShortCircuit"), - "Request was short circuited at resource filter '{ResourceFilter}'."); - _resultFilterShortCircuit = LoggerMessage.Define( LogLevel.Debug, new EventId(5, "ResultFilterShortCircuit"), @@ -306,28 +210,11 @@ static MvcCoreLoggerExtensions() new EventId(1, "ForbidResultExecuting"), formatString: $"Executing {nameof(ForbidResult)} with authentication schemes ({{Schemes}}).", SkipEnabledCheckLogOptions); - - _signInResultExecuting = LoggerMessage.Define( - LogLevel.Information, - new EventId(1, "SignInResultExecuting"), - formatString: $"Executing {nameof(SignInResult)} with authentication scheme ({{Scheme}}) and the following principal: {{Principal}}."); - _signOutResultExecuting = LoggerMessage.Define( LogLevel.Information, new EventId(1, "SignOutResultExecuting"), formatString: $"Executing {nameof(SignOutResult)} with authentication schemes ({{Schemes}}).", SkipEnabledCheckLogOptions); - - _httpStatusCodeResultExecuting = LoggerMessage.Define( - LogLevel.Information, - new EventId(1, "HttpStatusCodeResultExecuting"), - "Executing StatusCodeResult, setting HTTP status code {StatusCode}"); - - _localRedirectResultExecuting = LoggerMessage.Define( - LogLevel.Information, - new EventId(1, "LocalRedirectResultExecuting"), - "Executing LocalRedirectResult, redirecting to {Destination}."); - _noFormatter = LoggerMessage.Define>( LogLevel.Warning, new EventId(1, "NoFormatter"), @@ -345,22 +232,6 @@ static MvcCoreLoggerExtensions() new EventId(2, "FormatterSelected"), "Selected output formatter '{OutputFormatter}' and content type '{ContentType}' to write the response.", SkipEnabledCheckLogOptions); - - _skippedContentNegotiation = LoggerMessage.Define( - LogLevel.Debug, - new EventId(3, "SkippedContentNegotiation"), - "Skipped content negotiation as content type '{ContentType}' is explicitly set for the response."); - - _noAcceptForNegotiation = LoggerMessage.Define( - LogLevel.Debug, - new EventId(4, "NoAcceptForNegotiation"), - "No information found on request to perform content negotiation."); - - _noFormatterFromNegotiation = LoggerMessage.Define>( - LogLevel.Debug, - new EventId(5, "NoFormatterFromNegotiation"), - "Could not find an output formatter based on content negotiation. Accepted types were ({AcceptTypes})"); - _inputFormatterSelected = LoggerMessage.Define( LogLevel.Debug, new EventId(1, "InputFormatterSelected"), @@ -384,63 +255,11 @@ static MvcCoreLoggerExtensions() new EventId(4, "RemoveFromBodyAttribute"), "To use model binding, remove the [FromBody] attribute from the property or parameter named '{ModelName}' with model type '{ModelType}'.", SkipEnabledCheckLogOptions); - - _redirectResultExecuting = LoggerMessage.Define( - LogLevel.Information, - new EventId(1, "RedirectResultExecuting"), - "Executing RedirectResult, redirecting to {Destination}."); - - _redirectToActionResultExecuting = LoggerMessage.Define( - LogLevel.Information, - new EventId(1, "RedirectToActionResultExecuting"), - "Executing RedirectResult, redirecting to {Destination}."); - - _redirectToRouteResultExecuting = LoggerMessage.Define( - LogLevel.Information, - new EventId(1, "RedirectToRouteResultExecuting"), - "Executing RedirectToRouteResult, redirecting to {Destination} from route {RouteName}."); - - _redirectToPageResultExecuting = LoggerMessage.Define( - LogLevel.Information, - new EventId(1, "RedirectToPageResultExecuting"), - "Executing RedirectToPageResult, redirecting to {Page}."); - _noActionsMatched = LoggerMessage.Define( LogLevel.Debug, new EventId(3, "NoActionsMatched"), "No actions matched the current request. Route values: {RouteValues}", SkipEnabledCheckLogOptions); - - _featureNotFound = LoggerMessage.Define( - LogLevel.Warning, - new EventId(1, "FeatureNotFound"), - "A request body size limit could not be applied. This server does not support the IHttpRequestBodySizeFeature."); - - _featureIsReadOnly = LoggerMessage.Define( - LogLevel.Warning, - new EventId(2, "FeatureIsReadOnly"), - "A request body size limit could not be applied. The IHttpRequestBodySizeFeature for the server is read-only."); - - _maxRequestBodySizeSet = LoggerMessage.Define( - LogLevel.Debug, - new EventId(3, "MaxRequestBodySizeSet"), - "The maximum request body size has been set to {RequestSize}."); - - _requestBodySizeLimitDisabled = LoggerMessage.Define( - LogLevel.Debug, - new EventId(3, "RequestBodySizeLimitDisabled"), - "The request body size limit has been disabled."); - - _cannotApplyRequestFormLimits = LoggerMessage.Define( - LogLevel.Warning, - new EventId(1, "CannotApplyRequestFormLimits"), - "Unable to apply configured form options since the request form has already been read."); - - _appliedRequestFormLimits = LoggerMessage.Define( - LogLevel.Debug, - new EventId(2, "AppliedRequestFormLimits"), - "Applied the configured form options on the current request."); - _modelStateInvalidFilterExecuting = LoggerMessage.Define( LogLevel.Debug, new EventId(1, "ModelStateInvalidFilterExecuting"), @@ -451,72 +270,10 @@ static MvcCoreLoggerExtensions() new EventId(1, "InferredParameterSource"), "Inferred binding source for '{ParameterName}` on `{ActionName}` as {BindingSource}.", SkipEnabledCheckLogOptions); - - _unsupportedFormatFilterContentType = LoggerMessage.Define( - LogLevel.Debug, - new EventId(1, "UnsupportedFormatFilterContentType"), - "Could not find a media type for the format '{FormatFilterContentType}'."); - _actionDoesNotSupportFormatFilterContentType = LoggerMessage.Define( LogLevel.Debug, new EventId(2, "ActionDoesNotSupportFormatFilterContentType"), "Current action does not support the content type '{FormatFilterContentType}'. The supported content types are '{SupportedMediaTypes}'."); - - _cannotApplyFormatFilterContentType = LoggerMessage.Define( - LogLevel.Debug, - new EventId(3, "CannotApplyFormatFilterContentType"), - "Cannot apply content type '{FormatFilterContentType}' to the response as current action had explicitly set a preferred content type."); - - _notMostEffectiveFilter = LoggerMessage.Define( - LogLevel.Debug, - new EventId(4, "NotMostEffectiveFilter"), - "Execution of filter {OverriddenFilter} is preempted by filter {OverridingFilter} which is the most effective filter implementing policy {FilterPolicy}."); - - _actionDoesNotExplicitlySpecifyContentTypes = LoggerMessage.Define( - LogLevel.Debug, - new EventId(5, "ActionDoesNotExplicitlySpecifyContentTypes"), - "Current action does not explicitly specify any content types for the response."); - - _selectingOutputFormatterUsingAcceptHeader = LoggerMessage.Define>( - LogLevel.Debug, - new EventId(6, "SelectingOutputFormatterUsingAcceptHeader"), - "Attempting to select an output formatter based on Accept header '{AcceptHeader}'."); - - _selectingOutputFormatterUsingAcceptHeaderAndExplicitContentTypes = LoggerMessage.Define, MediaTypeCollection>( - LogLevel.Debug, - new EventId(7, "SelectingOutputFormatterUsingAcceptHeaderAndExplicitContentTypes"), - "Attempting to select an output formatter based on Accept header '{AcceptHeader}' and explicitly specified content types '{ExplicitContentTypes}'. The content types in the accept header must be a subset of the explicitly set content types."); - - _selectingOutputFormatterWithoutUsingContentTypes = LoggerMessage.Define( - LogLevel.Debug, - new EventId(8, "SelectingOutputFormatterWithoutUsingContentTypes"), - "Attempting to select an output formatter without using a content type as no explicit content types were specified for the response."); - - _selectingOutputFormatterUsingContentTypes = LoggerMessage.Define( - LogLevel.Debug, - new EventId(9, "SelectingOutputFormatterUsingContentTypes"), - "Attempting to select the first output formatter in the output formatters list which supports a content type from the explicitly specified content types '{ExplicitContentTypes}'."); - - _selectingFirstCanWriteFormatter = LoggerMessage.Define( - LogLevel.Debug, - new EventId(10, "SelectingFirstCanWriteFormatter"), - "Attempting to select the first formatter in the output formatters list which can write the result."); - - _registeredOutputFormatters = LoggerMessage.Define>( - LogLevel.Debug, - new EventId(11, "RegisteredOutputFormatters"), - "List of registered output formatters, in the following order: {OutputFormatters}"); - - _writingRangeToBody = LoggerMessage.Define( - LogLevel.Debug, - new EventId(17, "WritingRangeToBody"), - "Writing the requested range of bytes to the body..."); - - _registeredModelBinderProviders = LoggerMessage.Define( - LogLevel.Debug, - new EventId(12, "RegisteredModelBinderProviders"), - "Registered model binder providers, in the following order: {ModelBinderProviders}"); - _attemptingToBindPropertyModel = LoggerMessage.Define( LogLevel.Debug, new EventId(13, "AttemptingToBindPropertyModel"), @@ -555,17 +312,6 @@ static MvcCoreLoggerExtensions() LogLevel.Debug, new EventId(19, "CannotBindToFilesCollectionDueToUnsupportedContentType"), "Could not bind to model with name '{ModelName}' and type '{ModelType}' as the request did not have a content type of either 'application/x-www-form-urlencoded' or 'multipart/form-data'."); - - _cannotCreateHeaderModelBinder = LoggerMessage.Define( - LogLevel.Debug, - new EventId(20, "CannotCreateHeaderModelBinder"), - "Could not create a binder for type '{ModelType}' as this binder only supports simple types (like string, int, bool, enum) or a collection of simple types."); - - _noFilesFoundInRequest = LoggerMessage.Define( - LogLevel.Debug, - new EventId(21, "NoFilesFoundInRequest"), - "No files found in the request to bind the model to."); - _attemptingToBindParameter = LoggerMessage.Define( LogLevel.Debug, new EventId(22, "AttemptingToBindParameter"), @@ -629,12 +375,6 @@ static MvcCoreLoggerExtensions() LogLevel.Debug, new EventId(33, "NoKeyValueFormatForDictionaryModelBinder"), "Attempting to bind model with name '{ModelName}' using the format {ModelName}[key1]=value1&{ModelName}[key2]=value2"); - - _ifMatchPreconditionFailed = LoggerMessage.Define( - LogLevel.Debug, - new EventId(34, "IfMatchPreconditionFailed"), - "Current request's If-Match header check failed as the file's current etag '{CurrentETag}' does not match with any of the supplied etags."); - _ifUnmodifiedSincePreconditionFailed = LoggerMessage.Define( LogLevel.Debug, new EventId(35, "IfUnmodifiedSincePreconditionFailed"), @@ -649,12 +389,6 @@ static MvcCoreLoggerExtensions() LogLevel.Debug, new EventId(37, "IfRangeETagPreconditionFailed"), "Could not serve range as the file's current etag '{CurrentETag}' does not match the If-Range etag '{IfRangeETag}'."); - - _notEnabledForRangeProcessing = LoggerMessage.Define( - LogLevel.Debug, - new EventId(38, "NotEnabledForRangeProcessing"), - $"The file result has not been enabled for processing range requests. To enable it, set the property '{nameof(FileResult.EnableRangeProcessing)}' on the result to 'true'."); - _attemptingToBindProperty = LoggerMessage.Define( LogLevel.Debug, new EventId(39, "AttemptingToBindProperty"), @@ -720,39 +454,6 @@ static MvcCoreLoggerExtensions() "Replacing {InitialActionResultType} with status code {StatusCode} with {ReplacedActionResultType}."); } - public static void RegisteredOutputFormatters(this ILogger logger, IEnumerable outputFormatters) - { - _registeredOutputFormatters(logger, outputFormatters, null); - } - - public static void SelectingOutputFormatterUsingAcceptHeaderAndExplicitContentTypes( - this ILogger logger, - IEnumerable acceptHeader, - MediaTypeCollection mediaTypeCollection) - { - _selectingOutputFormatterUsingAcceptHeaderAndExplicitContentTypes(logger, acceptHeader, mediaTypeCollection, null); - } - - public static void SelectingOutputFormatterUsingAcceptHeader(this ILogger logger, IEnumerable acceptHeader) - { - _selectingOutputFormatterUsingAcceptHeader(logger, acceptHeader, null); - } - - public static void SelectingOutputFormatterUsingContentTypes(this ILogger logger, MediaTypeCollection mediaTypeCollection) - { - _selectingOutputFormatterUsingContentTypes(logger, mediaTypeCollection, null); - } - - public static void SelectingOutputFormatterWithoutUsingContentTypes(this ILogger logger) - { - _selectingOutputFormatterWithoutUsingContentTypes(logger, null); - } - - public static void SelectFirstCanWriteFormatter(this ILogger logger) - { - _selectingFirstCanWriteFormatter(logger, null); - } - public static IDisposable ActionScope(this ILogger logger, ActionDescriptor action) { return logger.BeginScope(new ActionLogScope(action)); @@ -917,21 +618,6 @@ public static void ChallengeResultExecuting(this ILogger logger, IList s } } - public static void ContentResultExecuting(this ILogger logger, string contentType) - { - _contentResultExecuting(logger, contentType, null); - } - - public static void BeforeExecutingActionResult(this ILogger logger, IActionResult actionResult) - { - _beforeExecutingActionResult(logger, actionResult.GetType(), null); - } - - public static void AfterExecutingActionResult(this ILogger logger, IActionResult actionResult) - { - _afterExecutingActionResult(logger, actionResult.GetType(), null); - } - public static void ActionMethodExecuting(this ILogger logger, ControllerContext context, object[] arguments) { if (logger.IsEnabled(LogLevel.Information)) @@ -963,20 +649,6 @@ public static void ActionMethodExecuted(this ILogger logger, ControllerContext c } } - public static void AmbiguousActions(this ILogger logger, string actionNames) - { - _ambiguousActions(logger, actionNames, null); - } - - public static void ConstraintMismatch( - this ILogger logger, - string actionName, - string actionId, - IActionConstraint actionConstraint) - { - _constraintMismatch(logger, actionName, actionId, actionConstraint, null); - } - public static void ExecutingFileResult(this ILogger logger, FileResult fileResult) { if (logger.IsEnabled(LogLevel.Information)) @@ -995,30 +667,6 @@ public static void ExecutingFileResult(this ILogger logger, FileResult fileResul } } - public static void NotEnabledForRangeProcessing(this ILogger logger) - { - _notEnabledForRangeProcessing(logger, null); - } - - public static void WritingRangeToBody(this ILogger logger) - { - _writingRangeToBody(logger, null); - } - - public static void AuthorizationFailure( - this ILogger logger, - IFilterMetadata filter) - { - _authorizationFailure(logger, filter, null); - } - - public static void ResourceFilterShortCircuited( - this ILogger logger, - IFilterMetadata filter) - { - _resourceFilterShortCircuit(logger, filter, null); - } - public static void ResultFilterShortCircuited( this ILogger logger, IFilterMetadata filter) @@ -1048,11 +696,6 @@ public static void ForbidResultExecuting(this ILogger logger, IList auth } } - public static void SignInResultExecuting(this ILogger logger, string authenticationScheme, ClaimsPrincipal principal) - { - _signInResultExecuting(logger, authenticationScheme, principal, null); - } - public static void SignOutResultExecuting(this ILogger logger, IList authenticationSchemes) { if (logger.IsEnabled(LogLevel.Information)) @@ -1061,16 +704,6 @@ public static void SignOutResultExecuting(this ILogger logger, IList aut } } - public static void HttpStatusCodeResultExecuting(this ILogger logger, int statusCode) - { - _httpStatusCodeResultExecuting(logger, statusCode, null); - } - - public static void LocalRedirectResultExecuting(this ILogger logger, string destination) - { - _localRedirectResultExecuting(logger, destination, null); - } - public static void ObjectResultExecuting(this ILogger logger, ObjectResult result, object value) { if (logger.IsEnabled(LogLevel.Information)) @@ -1111,21 +744,6 @@ public static void FormatterSelected( } } - public static void SkippedContentNegotiation(this ILogger logger, string contentType) - { - _skippedContentNegotiation(logger, contentType, null); - } - - public static void NoAcceptForNegotiation(this ILogger logger) - { - _noAcceptForNegotiation(logger, null); - } - - public static void NoFormatterFromNegotiation(this ILogger logger, IList acceptTypes) - { - _noFormatterFromNegotiation(logger, acceptTypes, null); - } - public static void InputFormatterSelected( this ILogger logger, IInputFormatter inputFormatter, @@ -1167,64 +785,6 @@ public static void NoInputFormatterSelected( } } - public static void RedirectResultExecuting(this ILogger logger, string destination) - { - _redirectResultExecuting(logger, destination, null); - } - - public static void RedirectToActionResultExecuting(this ILogger logger, string destination) - { - _redirectToActionResultExecuting(logger, destination, null); - } - - public static void RedirectToRouteResultExecuting(this ILogger logger, string destination, string routeName) - { - _redirectToRouteResultExecuting(logger, destination, routeName, null); - } - - public static void RedirectToPageResultExecuting(this ILogger logger, string page) - => _redirectToPageResultExecuting(logger, page, null); - - public static void FeatureNotFound(this ILogger logger) - { - _featureNotFound(logger, null); - } - - public static void FeatureIsReadOnly(this ILogger logger) - { - _featureIsReadOnly(logger, null); - } - - public static void MaxRequestBodySizeSet(this ILogger logger, string requestSize) - { - _maxRequestBodySizeSet(logger, requestSize, null); - } - - public static void RequestBodySizeLimitDisabled(this ILogger logger) - { - _requestBodySizeLimitDisabled(logger, null); - } - - public static void CannotApplyRequestFormLimits(this ILogger logger) - { - _cannotApplyRequestFormLimits(logger, null); - } - - public static void AppliedRequestFormLimits(this ILogger logger) - { - _appliedRequestFormLimits(logger, null); - } - - public static void NotMostEffectiveFilter(this ILogger logger, Type overridenFilter, Type overridingFilter, Type policyType) - { - _notMostEffectiveFilter(logger, overridenFilter, overridingFilter, policyType, null); - } - - public static void UnsupportedFormatFilterContentType(this ILogger logger, string format) - { - _unsupportedFormatFilterContentType(logger, format, null); - } - public static void ActionDoesNotSupportFormatFilterContentType( this ILogger logger, string format, @@ -1233,16 +793,6 @@ public static void ActionDoesNotSupportFormatFilterContentType( _actionDoesNotSupportFormatFilterContentType(logger, format, supportedMediaTypes, null); } - public static void CannotApplyFormatFilterContentType(this ILogger logger, string format) - { - _cannotApplyFormatFilterContentType(logger, format, null); - } - - public static void ActionDoesNotExplicitlySpecifyContentTypes(this ILogger logger) - { - _actionDoesNotExplicitlySpecifyContentTypes(logger, null); - } - public static void ModelStateInvalidFilterExecuting(this ILogger logger) => _modelStateInvalidFilterExecuting(logger, null); public static void InferredParameterBindingSource( @@ -1256,11 +806,6 @@ public static void InferredParameterBindingSource( } } - public static void IfMatchPreconditionFailed(this ILogger logger, EntityTagHeaderValue etag) - { - _ifMatchPreconditionFailed(logger, etag, null); - } - public static void IfUnmodifiedSincePreconditionFailed( this ILogger logger, DateTimeOffset? lastModified, @@ -1285,11 +830,6 @@ public static void IfRangeETagPreconditionFailed( _ifRangeETagPreconditionFailed(logger, currentETag, ifRangeTag, null); } - public static void RegisteredModelBinderProviders(this ILogger logger, IModelBinderProvider[] providers) - { - _registeredModelBinderProviders(logger, providers, null); - } - public static void FoundNoValueInRequest(this ILogger logger, ModelBindingContext bindingContext) { if (!logger.IsEnabled(LogLevel.Debug)) @@ -1347,16 +887,6 @@ public static void CannotCreateHeaderModelBinderCompatVersion_2_0(this ILogger l _cannotCreateHeaderModelBinderCompatVersion_2_0(logger, modelType, null); } - public static void CannotCreateHeaderModelBinder(this ILogger logger, Type modelType) - { - _cannotCreateHeaderModelBinder(logger, modelType, null); - } - - public static void NoFilesFoundInRequest(this ILogger logger) - { - _noFilesFoundInRequest(logger, null); - } - public static void AttemptingToBindModel(this ILogger logger, ModelBindingContext bindingContext) { if (!logger.IsEnabled(LogLevel.Debug)) diff --git a/src/Mvc/Mvc.Core/src/SignInResult.cs b/src/Mvc/Mvc.Core/src/SignInResult.cs index 8f468ba14c0d..05129a07fe26 100644 --- a/src/Mvc/Mvc.Core/src/SignInResult.cs +++ b/src/Mvc/Mvc.Core/src/SignInResult.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc; /// /// An that on execution invokes . /// -public class SignInResult : ActionResult +public partial class SignInResult : ActionResult { /// /// Initializes a new instance of with the @@ -85,9 +85,14 @@ public override Task ExecuteResultAsync(ActionContext context) var httpContext = context.HttpContext; var loggerFactory = httpContext.RequestServices.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - - logger.SignInResultExecuting(AuthenticationScheme, Principal); + Log.SignInResultExecuting(logger, AuthenticationScheme, Principal); return httpContext.SignInAsync(AuthenticationScheme, Principal, Properties); } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Information, $"Executing {nameof(SignInResult)} with authentication scheme ({{Scheme}}) and the following principal: {{Principal}}.", EventName = "SignInResultExecuting")] + public static partial void SignInResultExecuting(ILogger logger, string? scheme, ClaimsPrincipal principal); + } } diff --git a/src/Mvc/Mvc.Core/src/StatusCodeResult.cs b/src/Mvc/Mvc.Core/src/StatusCodeResult.cs index 0f3b695cdc68..bd465c718286 100644 --- a/src/Mvc/Mvc.Core/src/StatusCodeResult.cs +++ b/src/Mvc/Mvc.Core/src/StatusCodeResult.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc; /// Represents an that when executed will /// produce an HTTP response with the given response status code. /// -public class StatusCodeResult : ActionResult, IClientErrorActionResult +public partial class StatusCodeResult : ActionResult, IClientErrorActionResult { /// /// Initializes a new instance of the class @@ -41,9 +41,14 @@ public override void ExecuteResult(ActionContext context) var httpContext = context.HttpContext; var factory = httpContext.RequestServices.GetRequiredService(); var logger = factory.CreateLogger(); - - logger.HttpStatusCodeResultExecuting(StatusCode); + Log.HttpStatusCodeResultExecuting(logger, StatusCode); httpContext.Response.StatusCode = StatusCode; } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Information, "Executing StatusCodeResult, setting HTTP status code {StatusCode}", EventName = "HttpStatusCodeResultExecuting")] + public static partial void HttpStatusCodeResultExecuting(ILogger logger, int statusCode); + } } diff --git a/src/Mvc/Mvc.Formatters.Xml/src/LoggerExtensions.cs b/src/Mvc/Mvc.Formatters.Xml/src/LoggerExtensions.cs deleted file mode 100644 index a5b30d835b65..000000000000 --- a/src/Mvc/Mvc.Formatters.Xml/src/LoggerExtensions.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.Extensions.Logging; - -namespace Microsoft.AspNetCore.Mvc.Formatters.Xml; - -internal static class LoggerExtensions -{ - private static readonly Action _failedToCreateXmlSerializer; - private static readonly Action _failedToCreateDataContractSerializer; - - static LoggerExtensions() - { - _failedToCreateXmlSerializer = LoggerMessage.Define( - LogLevel.Warning, - new EventId(1, "FailedToCreateXmlSerializer"), - "An error occurred while trying to create an XmlSerializer for the type '{Type}'."); - - _failedToCreateDataContractSerializer = LoggerMessage.Define( - LogLevel.Warning, - new EventId(2, "FailedToCreateDataContractSerializer"), - "An error occurred while trying to create a DataContractSerializer for the type '{Type}'."); - } - - public static void FailedToCreateXmlSerializer(this ILogger logger, string typeName, Exception exception) - { - _failedToCreateXmlSerializer(logger, typeName, exception); - } - - public static void FailedToCreateDataContractSerializer(this ILogger logger, string typeName, Exception exception) - { - _failedToCreateDataContractSerializer(logger, typeName, exception); - } -} diff --git a/src/Mvc/Mvc.Formatters.Xml/src/XmlDataContractSerializerOutputFormatter.cs b/src/Mvc/Mvc.Formatters.Xml/src/XmlDataContractSerializerOutputFormatter.cs index 42299c9e33b6..0f5082a43d74 100644 --- a/src/Mvc/Mvc.Formatters.Xml/src/XmlDataContractSerializerOutputFormatter.cs +++ b/src/Mvc/Mvc.Formatters.Xml/src/XmlDataContractSerializerOutputFormatter.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters; /// This class handles serialization of objects /// to XML using /// -public class XmlDataContractSerializerOutputFormatter : TextOutputFormatter +public partial class XmlDataContractSerializerOutputFormatter : TextOutputFormatter { private readonly ConcurrentDictionary _serializerCache = new ConcurrentDictionary(); private readonly ILogger _logger; @@ -169,7 +169,7 @@ protected override bool CanWriteType(Type? type) } catch (Exception ex) { - _logger.FailedToCreateDataContractSerializer(type.FullName!, ex); + Log.FailedToCreateDataContractSerializer(_logger, type.FullName!, ex); // We do not surface the caught exception because if CanWriteResult returns // false, then this Formatter is not picked up at all. @@ -330,22 +330,20 @@ protected virtual DataContractSerializer GetCachedSerializer(Type type) return (DataContractSerializer)serializer!; } - private static class Log + private static partial class Log { - private static readonly LogDefineOptions SkipEnabledCheckLogOptions = new() { SkipEnabledCheck = true }; - - private static readonly Action _bufferingAsyncEnumerable = LoggerMessage.Define( - LogLevel.Debug, - new EventId(1, "BufferingAsyncEnumerable"), - "Buffering IAsyncEnumerable instance of type '{Type}'.", - SkipEnabledCheckLogOptions); + [LoggerMessage(1, LogLevel.Debug, "Buffering IAsyncEnumerable instance of type '{Type}'.", EventName = "BufferingAsyncEnumerable", SkipEnabledCheck = true)] + private static partial void BufferingAsyncEnumerable(ILogger logger, string type); public static void BufferingAsyncEnumerable(ILogger logger, object asyncEnumerable) { if (logger.IsEnabled(LogLevel.Debug)) { - _bufferingAsyncEnumerable(logger, asyncEnumerable.GetType().FullName!, null); + BufferingAsyncEnumerable(logger, asyncEnumerable.GetType().FullName!); } } + + [LoggerMessage(2, LogLevel.Warning, "An error occurred while trying to create a DataContractSerializer for the type '{Type}'.", EventName = "FailedToCreateDataContractSerializer")] + public static partial void FailedToCreateDataContractSerializer(ILogger logger, string type, Exception exception); } } diff --git a/src/Mvc/Mvc.Formatters.Xml/src/XmlSerializerOutputFormatter.cs b/src/Mvc/Mvc.Formatters.Xml/src/XmlSerializerOutputFormatter.cs index 3f19c13081b4..5044a0cf60a3 100644 --- a/src/Mvc/Mvc.Formatters.Xml/src/XmlSerializerOutputFormatter.cs +++ b/src/Mvc/Mvc.Formatters.Xml/src/XmlSerializerOutputFormatter.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters; /// This class handles serialization of objects /// to XML using /// -public class XmlSerializerOutputFormatter : TextOutputFormatter +public partial class XmlSerializerOutputFormatter : TextOutputFormatter { private readonly ConcurrentDictionary _serializerCache = new ConcurrentDictionary(); private readonly ILogger _logger; @@ -145,7 +145,7 @@ protected override bool CanWriteType(Type? type) } catch (Exception ex) { - _logger.FailedToCreateXmlSerializer(type.FullName!, ex); + Log.FailedToCreateXmlSerializer(_logger, type.FullName!, ex); // We do not surface the caught exception because if CanWriteResult returns // false, then this Formatter is not picked up at all. @@ -316,22 +316,20 @@ protected virtual XmlSerializer GetCachedSerializer(Type type) return (XmlSerializer)serializer!; } - private static class Log + private static partial class Log { - private static readonly LogDefineOptions SkipEnabledCheckLogOptions = new() { SkipEnabledCheck = true }; - - private static readonly Action _bufferingAsyncEnumerable = LoggerMessage.Define( - LogLevel.Debug, - new EventId(1, "BufferingAsyncEnumerable"), - "Buffering IAsyncEnumerable instance of type '{Type}'.", - SkipEnabledCheckLogOptions); + [LoggerMessage(1, LogLevel.Debug, "Buffering IAsyncEnumerable instance of type '{Type}'.", EventName = "BufferingAsyncEnumerable", SkipEnabledCheck = true)] + private static partial void BufferingAsyncEnumerable(ILogger logger, string type); public static void BufferingAsyncEnumerable(ILogger logger, object asyncEnumerable) { if (logger.IsEnabled(LogLevel.Debug)) { - _bufferingAsyncEnumerable(logger, asyncEnumerable.GetType().FullName!, null); + BufferingAsyncEnumerable(logger, asyncEnumerable.GetType().FullName!); } } + + [LoggerMessage(2, LogLevel.Warning, "An error occurred while trying to create an XmlSerializer for the type '{Type}'.", EventName = "FailedToCreateXmlSerializer")] + public static partial void FailedToCreateXmlSerializer(ILogger logger, string type, Exception exception); } } diff --git a/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonInputFormatter.cs b/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonInputFormatter.cs index 04038eb92759..61c0c03b0a12 100644 --- a/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonInputFormatter.cs +++ b/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonInputFormatter.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters; /// /// A for JSON content. /// -public class NewtonsoftJsonInputFormatter : TextInputFormatter, IInputFormatterExceptionPolicy +public partial class NewtonsoftJsonInputFormatter : TextInputFormatter, IInputFormatterExceptionPolicy { private readonly IArrayPool _charPool; private readonly ILogger _logger; @@ -329,8 +329,7 @@ void ErrorHandler(object? sender, Newtonsoft.Json.Serialization.ErrorEventArgs e var metadata = GetPathMetadata(context.Metadata, path); var modelStateException = WrapExceptionForModelState(exception); context.ModelState.TryAddModelError(key, modelStateException, metadata); - - _logger.JsonInputException(exception); + Log.JsonInputException(_logger, exception); // Error must always be marked as handled // Failure to do so can cause the exception to be rethrown at every recursive level and @@ -453,4 +452,10 @@ private Exception WrapExceptionForModelState(Exception exception) // Not a known exception type, so we're not going to assume that it's safe. return exception; } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Debug, "JSON input formatter threw an exception.", EventName = "JsonInputException")] + public static partial void JsonInputException(ILogger logger, Exception exception); + } } diff --git a/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonLoggerExtensions.cs b/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonLoggerExtensions.cs deleted file mode 100644 index 023f54047e74..000000000000 --- a/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonLoggerExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.Extensions.Logging; - -namespace Microsoft.AspNetCore.Mvc.NewtonsoftJson; - -internal static class NewtonsoftJsonLoggerExtensions -{ - private static readonly Action _jsonInputFormatterException; - - static NewtonsoftJsonLoggerExtensions() - { - _jsonInputFormatterException = LoggerMessage.Define( - LogLevel.Debug, - new EventId(1, "JsonInputException"), - "JSON input formatter threw an exception."); - } - - public static void JsonInputException(this ILogger logger, Exception exception) - { - _jsonInputFormatterException(logger, exception); - } -} diff --git a/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonOutputFormatter.cs b/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonOutputFormatter.cs index 777689c568c8..a6f8703ce498 100644 --- a/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonOutputFormatter.cs +++ b/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonOutputFormatter.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters; /// /// A for JSON content. /// -public class NewtonsoftJsonOutputFormatter : TextOutputFormatter +public partial class NewtonsoftJsonOutputFormatter : TextOutputFormatter { private readonly IArrayPool _charPool; private readonly MvcOptions _mvcOptions; @@ -245,21 +245,16 @@ private static JsonSerializerSettings ShallowCopy(JsonSerializerSettings setting return copiedSettings; } - private static class Log + private static partial class Log { - private static readonly LogDefineOptions SkipEnabledCheckLogOptions = new() { SkipEnabledCheck = true }; - - private static readonly Action _bufferingAsyncEnumerable = LoggerMessage.Define( - LogLevel.Debug, - new EventId(1, "BufferingAsyncEnumerable"), - "Buffering IAsyncEnumerable instance of type '{Type}'.", - SkipEnabledCheckLogOptions); + [LoggerMessage(1, LogLevel.Debug, "Buffering IAsyncEnumerable instance of type '{Type}'.", EventName = "BufferingAsyncEnumerable", SkipEnabledCheck = true)] + private static partial void BufferingAsyncEnumerable(ILogger logger, string? type); public static void BufferingAsyncEnumerable(ILogger logger, object asyncEnumerable) { if (logger.IsEnabled(LogLevel.Debug)) { - _bufferingAsyncEnumerable(logger, asyncEnumerable.GetType().FullName, null); + BufferingAsyncEnumerable(logger, asyncEnumerable.GetType().FullName); } } } diff --git a/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonResultExecutor.cs b/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonResultExecutor.cs index 4f5177946212..179e382b26b9 100644 --- a/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonResultExecutor.cs +++ b/src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonResultExecutor.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Mvc.NewtonsoftJson; /// /// Executes a to write to the response. /// -internal class NewtonsoftJsonResultExecutor : IActionResultExecutor +internal partial class NewtonsoftJsonResultExecutor : IActionResultExecutor { private static readonly string DefaultContentType = new MediaTypeHeaderValue("application/json") { @@ -185,36 +185,28 @@ private JsonSerializerSettings GetSerializerSettings(JsonResult result) } } - private static class Log + private static partial class Log { - private static readonly LogDefineOptions SkipEnabledCheckLogOptions = new() { SkipEnabledCheck = true }; + [LoggerMessage(1, LogLevel.Debug, "Buffering IAsyncEnumerable instance of type '{Type}'.", EventName = "BufferingAsyncEnumerable", SkipEnabledCheck = true)] + private static partial void BufferingAsyncEnumerable(ILogger logger, string? type); - private static readonly Action _jsonResultExecuting = LoggerMessage.Define( - LogLevel.Information, - new EventId(1, "JsonResultExecuting"), - "Executing JsonResult, writing value of type '{Type}'.", - SkipEnabledCheckLogOptions); - - private static readonly Action _bufferingAsyncEnumerable = LoggerMessage.Define( - LogLevel.Debug, - new EventId(1, "BufferingAsyncEnumerable"), - "Buffering IAsyncEnumerable instance of type '{Type}'.", - SkipEnabledCheckLogOptions); - - public static void JsonResultExecuting(ILogger logger, object? value) + public static void BufferingAsyncEnumerable(ILogger logger, object asyncEnumerable) { - if (logger.IsEnabled(LogLevel.Information)) + if (logger.IsEnabled(LogLevel.Debug)) { - var type = value == null ? "null" : value.GetType().FullName; - _jsonResultExecuting(logger, type, null); + BufferingAsyncEnumerable(logger, asyncEnumerable.GetType().FullName); } } - public static void BufferingAsyncEnumerable(ILogger logger, object asyncEnumerable) + [LoggerMessage(2, LogLevel.Information, "Executing JsonResult, writing value of type '{Type}'.", EventName = "JsonResultExecuting", SkipEnabledCheck = true)] + private static partial void JsonResultExecuting(ILogger logger, string? type); + + public static void JsonResultExecuting(ILogger logger, object? value) { - if (logger.IsEnabled(LogLevel.Debug)) + if (logger.IsEnabled(LogLevel.Information)) { - _bufferingAsyncEnumerable(logger, asyncEnumerable.GetType().FullName, null); + var type = value == null ? "null" : value.GetType().FullName; + JsonResultExecuting(logger, type); } } } diff --git a/src/Mvc/Mvc.Razor.RuntimeCompilation/src/PageDirectiveFeature.cs b/src/Mvc/Mvc.Razor.RuntimeCompilation/src/PageDirectiveFeature.cs index e897047f20aa..08ce30d049e6 100644 --- a/src/Mvc/Mvc.Razor.RuntimeCompilation/src/PageDirectiveFeature.cs +++ b/src/Mvc/Mvc.Razor.RuntimeCompilation/src/PageDirectiveFeature.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Linq; using Microsoft.AspNetCore.Mvc.Razor.Extensions; using Microsoft.AspNetCore.Razor.Language; @@ -10,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation; -internal static class PageDirectiveFeature +internal static partial class PageDirectiveFeature { private static readonly RazorProjectEngine PageDirectiveEngine = RazorProjectEngine.Create(RazorConfiguration.Default, new EmptyRazorProjectFileSystem(), builder => { @@ -42,7 +43,7 @@ public static bool TryGetPageDirective(ILogger logger, RazorProjectItem projectI { if (pageDirective.DirectiveNode is MalformedDirectiveIntermediateNode malformedNode) { - logger.MalformedPageDirective(projectItem.FilePath, malformedNode.Diagnostics); + Log.MalformedPageDirective(logger, projectItem.FilePath, malformedNode.Diagnostics); } template = pageDirective.RouteTemplate; @@ -114,4 +115,24 @@ public NotFoundProjectItem(string basePath, string path, string? fileKind) public override Stream Read() => throw new NotSupportedException(); } } + + private static partial class Log + { + [LoggerMessage(104, LogLevel.Warning, "The page directive at '{FilePath}' is malformed. Please fix the following issues: {Diagnostics}", EventName = "MalformedPageDirective", SkipEnabledCheck = true)] + private static partial void MalformedPageDirective(ILogger logger, string filePath, string[] diagnostics); + + public static void MalformedPageDirective(ILogger logger, string filePath, IList diagnostics) + { + if (logger.IsEnabled(LogLevel.Warning)) + { + var messages = new string[diagnostics.Count]; + for (var i = 0; i < diagnostics.Count; i++) + { + messages[i] = diagnostics[i].GetMessage(CultureInfo.CurrentCulture); + } + + MalformedPageDirective(logger, filePath, messages); + } + } + } } diff --git a/src/Mvc/Mvc.Razor.RuntimeCompilation/src/RazorRuntimeCompilationLoggerExtensions.cs b/src/Mvc/Mvc.Razor.RuntimeCompilation/src/RazorRuntimeCompilationLoggerExtensions.cs deleted file mode 100644 index 0d9555f5dade..000000000000 --- a/src/Mvc/Mvc.Razor.RuntimeCompilation/src/RazorRuntimeCompilationLoggerExtensions.cs +++ /dev/null @@ -1,180 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; -using System.Globalization; -using Microsoft.AspNetCore.Razor.Language; -using Microsoft.Extensions.Logging; - -namespace Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation; - -internal static class MvcRazorLoggerExtensions -{ - private static readonly double TimestampToTicks = TimeSpan.TicksPerSecond / (double)Stopwatch.Frequency; - - private static readonly Action _generatedCodeToAssemblyCompilationStart; - private static readonly Action _generatedCodeToAssemblyCompilationEnd; - private static readonly Action _malformedPageDirective; - private static readonly Action _viewCompilerLocatedCompiledView; - private static readonly Action _viewCompilerNoCompiledViewsFound; - private static readonly Action _viewCompilerLocatedCompiledViewForPath; - private static readonly Action _viewCompilerRecompilingCompiledView; - private static readonly Action _viewCompilerCouldNotFindFileToCompileForPath; - private static readonly Action _viewCompilerFoundFileToCompileForPath; - private static readonly Action _viewCompilerInvalidatingCompiledFile; - - private static readonly Action _viewLookupCacheMiss; - private static readonly Action _viewLookupCacheHit; - private static readonly Action _precompiledViewFound; - - private static readonly LogDefineOptions SkipEnabledCheckLogOptions = new() { SkipEnabledCheck = true }; - - static MvcRazorLoggerExtensions() - { - _viewCompilerLocatedCompiledView = LoggerMessage.Define( - LogLevel.Debug, - 3, - "Initializing Razor view compiler with compiled view: '{ViewName}'."); - - _viewCompilerNoCompiledViewsFound = LoggerMessage.Define( - LogLevel.Debug, - 4, - "Initializing Razor view compiler with no compiled views."); - - _viewCompilerLocatedCompiledViewForPath = LoggerMessage.Define( - LogLevel.Trace, - 5, - "Located compiled view for view at path '{Path}'."); - - _viewCompilerLocatedCompiledViewForPath = LoggerMessage.Define( - LogLevel.Trace, - 5, - "Located compiled view for view at path '{Path}'."); - - _viewCompilerRecompilingCompiledView = LoggerMessage.Define( - LogLevel.Trace, - 6, - "Invalidating compiled view for view at path '{Path}'."); - - _viewCompilerCouldNotFindFileToCompileForPath = LoggerMessage.Define( - LogLevel.Trace, - 7, - "Could not find a file for view at path '{Path}'."); - - _viewCompilerFoundFileToCompileForPath = LoggerMessage.Define( - LogLevel.Trace, - 8, - "Found file at path '{Path}'."); - - _viewCompilerInvalidatingCompiledFile = LoggerMessage.Define( - LogLevel.Trace, - 9, - "Invalidating compiled view at path '{Path}' with a file since the checksum did not match."); - - _viewLookupCacheMiss = LoggerMessage.Define( - LogLevel.Debug, - 1, - "View lookup cache miss for view '{ViewName}' in controller '{ControllerName}'."); - - _viewLookupCacheHit = LoggerMessage.Define( - LogLevel.Debug, - 2, - "View lookup cache hit for view '{ViewName}' in controller '{ControllerName}'."); - - _precompiledViewFound = LoggerMessage.Define( - LogLevel.Debug, - 3, - "Using precompiled view for '{RelativePath}'."); - - _generatedCodeToAssemblyCompilationStart = LoggerMessage.Define( - LogLevel.Debug, - 1, - "Compilation of the generated code for the Razor file at '{FilePath}' started."); - - _generatedCodeToAssemblyCompilationEnd = LoggerMessage.Define( - LogLevel.Debug, - 2, - "Compilation of the generated code for the Razor file at '{FilePath}' completed in {ElapsedMilliseconds}ms."); - - _malformedPageDirective = LoggerMessage.Define( - LogLevel.Warning, - new EventId(104, "MalformedPageDirective"), - "The page directive at '{FilePath}' is malformed. Please fix the following issues: {Diagnostics}", - SkipEnabledCheckLogOptions); - } - - public static void ViewCompilerLocatedCompiledView(this ILogger logger, string view) - { - _viewCompilerLocatedCompiledView(logger, view, null); - } - - public static void ViewCompilerNoCompiledViewsFound(this ILogger logger) - { - _viewCompilerNoCompiledViewsFound(logger, null); - } - - public static void ViewCompilerLocatedCompiledViewForPath(this ILogger logger, string path) - { - _viewCompilerLocatedCompiledViewForPath(logger, path, null); - } - - public static void ViewCompilerCouldNotFindFileAtPath(this ILogger logger, string path) - { - _viewCompilerCouldNotFindFileToCompileForPath(logger, path, null); - } - - public static void ViewCompilerFoundFileToCompile(this ILogger logger, string path) - { - _viewCompilerFoundFileToCompileForPath(logger, path, null); - } - - public static void ViewCompilerInvalidingCompiledFile(this ILogger logger, string path) - { - _viewCompilerInvalidatingCompiledFile(logger, path, null); - } - - public static void ViewLookupCacheMiss(this ILogger logger, string viewName, string controllerName) - { - _viewLookupCacheMiss(logger, viewName, controllerName, null); - } - - public static void ViewLookupCacheHit(this ILogger logger, string viewName, string controllerName) - { - _viewLookupCacheHit(logger, viewName, controllerName, null); - } - - public static void PrecompiledViewFound(this ILogger logger, string relativePath) - { - _precompiledViewFound(logger, relativePath, null); - } - - public static void GeneratedCodeToAssemblyCompilationStart(this ILogger logger, string filePath) - { - _generatedCodeToAssemblyCompilationStart(logger, filePath, null); - } - - public static void GeneratedCodeToAssemblyCompilationEnd(this ILogger logger, string filePath, long startTimestamp) - { - // Don't log if logging wasn't enabled at start of request as time will be wildly wrong. - if (startTimestamp != 0) - { - var currentTimestamp = Stopwatch.GetTimestamp(); - var elapsed = new TimeSpan((long)(TimestampToTicks * (currentTimestamp - startTimestamp))); - _generatedCodeToAssemblyCompilationEnd(logger, filePath, elapsed.TotalMilliseconds, null); - } - } - - public static void MalformedPageDirective(this ILogger logger, string filePath, IList diagnostics) - { - if (logger.IsEnabled(LogLevel.Warning)) - { - var messages = new string[diagnostics.Count]; - for (var i = 0; i < diagnostics.Count; i++) - { - messages[i] = diagnostics[i].GetMessage(CultureInfo.CurrentCulture); - } - - _malformedPageDirective(logger, filePath, messages, null); - } - } -} diff --git a/src/Mvc/Mvc.Razor.RuntimeCompilation/src/RuntimeViewCompiler.cs b/src/Mvc/Mvc.Razor.RuntimeCompilation/src/RuntimeViewCompiler.cs index 31914c918463..c075ff7fc54a 100644 --- a/src/Mvc/Mvc.Razor.RuntimeCompilation/src/RuntimeViewCompiler.cs +++ b/src/Mvc/Mvc.Razor.RuntimeCompilation/src/RuntimeViewCompiler.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation; -internal class RuntimeViewCompiler : IViewCompiler +internal partial class RuntimeViewCompiler : IViewCompiler { private readonly object _cacheLock = new object(); private readonly Dictionary _precompiledViews; @@ -84,7 +84,7 @@ public RuntimeViewCompiler( foreach (var precompiledView in precompiledViews) { - logger.ViewCompilerLocatedCompiledView(precompiledView.RelativePath); + Log.ViewCompilerLocatedCompiledView(_logger, precompiledView.RelativePath); if (!_precompiledViews.ContainsKey(precompiledView.RelativePath)) { @@ -96,7 +96,7 @@ public RuntimeViewCompiler( if (_precompiledViews.Count == 0) { - logger.ViewCompilerNoCompiledViewsFound(); + Log.ViewCompilerNoCompiledViewsFound(_logger); } } @@ -144,7 +144,7 @@ private Task OnCacheMiss(string normalizedPath) if (_precompiledViews.TryGetValue(normalizedPath, out var precompiledView)) { - _logger.ViewCompilerLocatedCompiledViewForPath(normalizedPath); + Log.ViewCompilerLocatedCompiledViewForPath(_logger, normalizedPath); item = CreatePrecompiledWorkItem(normalizedPath, precompiledView); } else @@ -192,7 +192,7 @@ private Task OnCacheMiss(string normalizedPath) return taskSource.Task; } - _logger.ViewCompilerInvalidingCompiledFile(item.NormalizedPath); + Log.ViewCompilerInvalidatingCompiledFile(_logger, item.NormalizedPath); try { var descriptor = CompileAndEmit(normalizedPath); @@ -264,7 +264,7 @@ private ViewCompilerWorkItem CreateRuntimeCompilationWorkItem(string normalizedP var projectItem = _projectEngine.FileSystem.GetItem(normalizedPath, fileKind: null); if (!projectItem.Exists) { - _logger.ViewCompilerCouldNotFindFileAtPath(normalizedPath); + Log.ViewCompilerCouldNotFindFileAtPath(_logger, normalizedPath); // If the file doesn't exist, we can't do compilation right now - we still want to cache // the fact that we tried. This will allow us to re-trigger compilation if the view file @@ -285,7 +285,7 @@ private ViewCompilerWorkItem CreateRuntimeCompilationWorkItem(string normalizedP }; } - _logger.ViewCompilerFoundFileToCompile(normalizedPath); + Log.ViewCompilerFoundFileToCompile(_logger, normalizedPath); GetChangeTokensFromImports(expirationTokens, projectItem); @@ -353,7 +353,7 @@ protected virtual CompiledViewDescriptor CompileAndEmit(string relativePath) internal Assembly CompileAndEmit(RazorCodeDocument codeDocument, string generatedCode) { - _logger.GeneratedCodeToAssemblyCompilationStart(codeDocument.Source.FilePath); + Log.GeneratedCodeToAssemblyCompilationStart(_logger, codeDocument.Source.FilePath); var startTimestamp = _logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : 0; @@ -384,7 +384,7 @@ internal Assembly CompileAndEmit(RazorCodeDocument codeDocument, string generate pdbStream?.Seek(0, SeekOrigin.Begin); var assembly = Assembly.Load(assemblyStream.ToArray(), pdbStream?.ToArray()); - _logger.GeneratedCodeToAssemblyCompilationEnd(codeDocument.Source.FilePath, startTimestamp); + Log.GeneratedCodeToAssemblyCompilationEnd(_logger, codeDocument.Source.FilePath, startTimestamp); return assembly; } @@ -426,4 +426,47 @@ private class ViewCompilerWorkItem public CompiledViewDescriptor Descriptor { get; set; } = default!; } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Debug, "Compilation of the generated code for the Razor file at '{FilePath}' started.")] + public static partial void GeneratedCodeToAssemblyCompilationStart(ILogger logger, string filePath); + + [LoggerMessage(2, LogLevel.Debug, "Compilation of the generated code for the Razor file at '{FilePath}' completed in {ElapsedMilliseconds}ms.")] + private static partial void GeneratedCodeToAssemblyCompilationEnd(ILogger logger, string filePath, double elapsedMilliseconds); + + public static void GeneratedCodeToAssemblyCompilationEnd(ILogger logger, string filePath, long startTimestamp) + { + // Don't log if logging wasn't enabled at start of request as time will be wildly wrong. + if (startTimestamp != 0) + { + var currentTimestamp = Stopwatch.GetTimestamp(); + var elapsed = new TimeSpan((long)(TimestampToTicks * (currentTimestamp - startTimestamp))); + GeneratedCodeToAssemblyCompilationEnd(logger, filePath, elapsed.TotalMilliseconds); + } + } + + private static readonly double TimestampToTicks = TimeSpan.TicksPerSecond / (double)Stopwatch.Frequency; + + [LoggerMessage(3, LogLevel.Debug, "Initializing Razor view compiler with compiled view: '{ViewName}'.")] + public static partial void ViewCompilerLocatedCompiledView(ILogger logger, string viewName); + + [LoggerMessage(4, LogLevel.Debug, "Initializing Razor view compiler with no compiled views.")] + public static partial void ViewCompilerNoCompiledViewsFound(ILogger logger); + + [LoggerMessage(5, LogLevel.Trace, "Located compiled view for view at path '{Path}'.")] + public static partial void ViewCompilerLocatedCompiledViewForPath(ILogger logger, string path); + + [LoggerMessage(6, LogLevel.Trace, "Invalidating compiled view for view at path '{Path}'.")] + public static partial void ViewCompilerRecompilingCompiledView(ILogger logger, string path); + + [LoggerMessage(7, LogLevel.Trace, "Could not find a file for view at path '{Path}'.")] + public static partial void ViewCompilerCouldNotFindFileAtPath(ILogger logger, string path); + + [LoggerMessage(8, LogLevel.Trace, "Found file at path '{Path}'.")] + public static partial void ViewCompilerFoundFileToCompile(ILogger logger, string path); + + [LoggerMessage(9, LogLevel.Trace, "Invalidating compiled view at path '{Path}' with a file since the checksum did not match.")] + public static partial void ViewCompilerInvalidatingCompiledFile(ILogger logger, string path); + } } diff --git a/src/Mvc/Mvc.Razor/src/Compilation/DefaultViewCompiler.cs b/src/Mvc/Mvc.Razor/src/Compilation/DefaultViewCompiler.cs index a34fa834f1dd..97cb48b2636b 100644 --- a/src/Mvc/Mvc.Razor/src/Compilation/DefaultViewCompiler.cs +++ b/src/Mvc/Mvc.Razor/src/Compilation/DefaultViewCompiler.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation; /// Caches the result of runtime compilation of Razor files for the duration of the application lifetime. /// // This name is hardcoded in RazorRuntimeCompilationMvcCoreBuilderExtensions. Make sure it's updated if this is ever renamed. -internal class DefaultViewCompiler : IViewCompiler +internal partial class DefaultViewCompiler : IViewCompiler { private readonly ApplicationPartManager _applicationPartManager; private readonly ConcurrentDictionary _normalizedPathCache; @@ -53,7 +53,7 @@ private void EnsureCompiledViews(ILogger logger) foreach (var compiledView in viewsFeature.ViewDescriptors) { - logger.ViewCompilerLocatedCompiledView(compiledView.RelativePath); + Log.ViewCompilerLocatedCompiledView(logger, compiledView.RelativePath); if (!compiledViews.ContainsKey(compiledView.RelativePath)) { @@ -65,7 +65,7 @@ private void EnsureCompiledViews(ILogger logger) if (compiledViews.Count == 0) { - logger.ViewCompilerNoCompiledViewsFound(); + Log.ViewCompilerNoCompiledViewsFound(logger); } // Safe races should be ok. We would end up logging multiple times @@ -108,7 +108,7 @@ public Task CompileAsync(string relativePath) } // Entry does not exist. Attempt to create one. - _logger.ViewCompilerCouldNotFindFileAtPath(relativePath); + Log.ViewCompilerCouldNotFindFileAtPath(_logger, relativePath); return Task.FromResult(new CompiledViewDescriptor { RelativePath = normalizedPath, @@ -132,4 +132,16 @@ private string GetNormalizedPath(string relativePath) return normalizedPath; } + + private static partial class Log + { + [LoggerMessage(3, LogLevel.Debug, "Initializing Razor view compiler with compiled view: '{ViewName}'.", EventName = "ViewCompilerLocatedCompiledView")] + public static partial void ViewCompilerLocatedCompiledView(ILogger logger, string viewName); + + [LoggerMessage(4, LogLevel.Debug, "Initializing Razor view compiler with no compiled views.", EventName = "ViewCompilerNoCompiledViewsFound")] + public static partial void ViewCompilerNoCompiledViewsFound(ILogger logger); + + [LoggerMessage(7, LogLevel.Trace, "Could not find a file for view at path '{Path}'.", EventName = "ViewCompilerCouldNotFindFileAtPath")] + public static partial void ViewCompilerCouldNotFindFileAtPath(ILogger logger, string path); + } } diff --git a/src/Mvc/Mvc.Razor/src/RazorViewEngine.cs b/src/Mvc/Mvc.Razor/src/RazorViewEngine.cs index bf2fd5b3ce24..70af1b03a14a 100644 --- a/src/Mvc/Mvc.Razor/src/RazorViewEngine.cs +++ b/src/Mvc/Mvc.Razor/src/RazorViewEngine.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor; /// by default. For the controllers in an area, views should exist in /// . /// -public class RazorViewEngine : IRazorViewEngine +public partial class RazorViewEngine : IRazorViewEngine { /// /// The view extension @@ -280,12 +280,12 @@ private ViewLocationCacheResult LocatePageFromViewLocations( if (!ViewLookupCache.TryGetValue(cacheKey, out ViewLocationCacheResult cacheResult)) { - _logger.ViewLookupCacheMiss(cacheKey.ViewName, cacheKey.ControllerName); + Log.ViewLookupCacheMiss(_logger, cacheKey.ViewName, cacheKey.ControllerName); cacheResult = OnCacheMiss(expanderContext, cacheKey); } else { - _logger.ViewLookupCacheHit(cacheKey.ViewName, cacheKey.ControllerName); + Log.ViewLookupCacheHit(_logger, cacheKey.ViewName, cacheKey.ControllerName); } return cacheResult; @@ -508,4 +508,13 @@ private static bool IsRelativePath(string name) // Though ./ViewName looks like a relative path, framework searches for that view using view locations. return name.EndsWith(ViewExtension, StringComparison.OrdinalIgnoreCase); } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Debug, "View lookup cache miss for view '{ViewName}' in controller '{ControllerName}'.", EventName = "ViewLookupCacheMiss")] + public static partial void ViewLookupCacheMiss(ILogger logger, string viewName, string? controllerName); + + [LoggerMessage(2, LogLevel.Debug, "View lookup cache hit for view '{ViewName}' in controller '{ControllerName}'.", EventName = "ViewLookupCacheHit")] + public static partial void ViewLookupCacheHit(ILogger logger, string viewName, string? controllerName); + } } diff --git a/src/Mvc/Mvc.Razor/src/TagHelpers/TagHelperComponentTagHelper.cs b/src/Mvc/Mvc.Razor/src/TagHelpers/TagHelperComponentTagHelper.cs index fd100e825ba1..58567bdad48c 100644 --- a/src/Mvc/Mvc.Razor/src/TagHelpers/TagHelperComponentTagHelper.cs +++ b/src/Mvc/Mvc.Razor/src/TagHelpers/TagHelperComponentTagHelper.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers; /// Initializes and processes the s added to the /// in the specified order. /// -public abstract class TagHelperComponentTagHelper : TagHelper +public abstract partial class TagHelperComponentTagHelper : TagHelper { private readonly ILogger _logger; private readonly IEnumerable _components; @@ -75,7 +75,7 @@ public override void Init(TagHelperContext context) component.Init(context); if (_logger.IsEnabled(LogLevel.Debug)) { - _logger.TagHelperComponentInitialized(component.GetType().FullName!); + Log.TagHelperComponentInitialized(_logger, component.GetType().FullName!); } } } @@ -88,8 +88,17 @@ public override async Task ProcessAsync(TagHelperContext context, TagHelperOutpu await component.ProcessAsync(context, output); if (_logger.IsEnabled(LogLevel.Debug)) { - _logger.TagHelperComponentProcessed(component.GetType().FullName!); + Log.TagHelperComponentProcessed(_logger, component.GetType().FullName!); } } } + + private static partial class Log + { + [LoggerMessage(2, LogLevel.Debug, "Tag helper component '{ComponentName}' initialized.", EventName = "TagHelperComponentInitialized")] + public static partial void TagHelperComponentInitialized(ILogger logger, string componentName); + + [LoggerMessage(3, LogLevel.Debug, "Tag helper component '{ComponentName}' processed.", EventName = "TagHelperComponentProcessed")] + public static partial void TagHelperComponentProcessed(ILogger logger, string componentName); + } } diff --git a/src/Mvc/Mvc.TagHelpers/src/Cache/DistributedCacheTagHelperService.cs b/src/Mvc/Mvc.TagHelpers/src/Cache/DistributedCacheTagHelperService.cs index cd6bd158e6ba..d296cdb2c8b8 100644 --- a/src/Mvc/Mvc.TagHelpers/src/Cache/DistributedCacheTagHelperService.cs +++ b/src/Mvc/Mvc.TagHelpers/src/Cache/DistributedCacheTagHelperService.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Concurrent; @@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Cache; /// /// /// -public class DistributedCacheTagHelperService : IDistributedCacheTagHelperService +public partial class DistributedCacheTagHelperService : IDistributedCacheTagHelperService { private readonly IDistributedCacheTagHelperStorage _storage; private readonly IDistributedCacheTagHelperFormatter _formatter; @@ -139,7 +139,7 @@ public async Task ProcessContentAsync(TagHelperOutput output, Cach } catch (Exception e) { - _logger.DistributedFormatterDeserializationException(storageKey, e); + Log.DistributedFormatterDeserializationException(_logger, storageKey, e); } finally { @@ -213,4 +213,10 @@ private static byte[] Decode(byte[] value, byte[] expectedKey) return decoded; } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Error, "Couldn't deserialize cached value for key {Key}.", EventName = "DistributedFormatterDeserializationException")] + public static partial void DistributedFormatterDeserializationException(ILogger logger, string key, Exception exception); + } } diff --git a/src/Mvc/Mvc.TagHelpers/src/MvcTagHelpersLoggerExtensions.cs b/src/Mvc/Mvc.TagHelpers/src/MvcTagHelpersLoggerExtensions.cs deleted file mode 100644 index e88cd6bf74d0..000000000000 --- a/src/Mvc/Mvc.TagHelpers/src/MvcTagHelpersLoggerExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.Extensions.Logging; - -namespace Microsoft.AspNetCore.Mvc.TagHelpers; - -internal static class MvcTagHelperLoggerExtensions -{ - private static readonly Action _distributedFormatterDeserializedFailed = LoggerMessage.Define( - LogLevel.Error, - new EventId(1, "DistributedFormatterDeserializationException"), - "Couldn't deserialize cached value for key {Key}."); - - public static void DistributedFormatterDeserializationException(this ILogger logger, string key, Exception exception) - { - _distributedFormatterDeserializedFailed(logger, key, exception); - } -} diff --git a/src/Mvc/Mvc.ViewFeatures/src/CookieTempDataProvider.cs b/src/Mvc/Mvc.ViewFeatures/src/CookieTempDataProvider.cs index 212cc89679d9..f924dd58e75c 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/CookieTempDataProvider.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/CookieTempDataProvider.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures; /// /// Provides data from cookie to the current object. /// -public class CookieTempDataProvider : ITempDataProvider +public partial class CookieTempDataProvider : ITempDataProvider { /// /// The name of the cookie. @@ -76,14 +76,13 @@ public IDictionary LoadTempData(HttpContext context) var protectedData = WebEncoders.Base64UrlDecode(encodedValue); var unprotectedData = _dataProtector.Unprotect(protectedData); var tempData = _tempDataSerializer.Deserialize(unprotectedData); - - _logger.TempDataCookieLoadSuccess(_options.Cookie.Name); + Log.TempDataCookieLoadSuccess(_logger, _options.Cookie.Name); return tempData; } } catch (Exception ex) { - _logger.TempDataCookieLoadFailure(_options.Cookie.Name, ex); + Log.TempDataCookieLoadFailure(_logger, _options.Cookie.Name, ex); // If we've failed, we want to try and clear the cookie so that this won't keep happening // over and over. @@ -94,7 +93,7 @@ public IDictionary LoadTempData(HttpContext context) } } - _logger.TempDataCookieNotFound(_options.Cookie.Name); + Log.TempDataCookieNotFound(_logger, _options.Cookie.Name); return new Dictionary(StringComparer.OrdinalIgnoreCase); } @@ -142,4 +141,16 @@ private void SetCookiePath(HttpContext httpContext, CookieOptions cookieOptions) } } } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Debug, "The temp data cookie {CookieName} was not found.", EventName = "TempDataCookieNotFound")] + public static partial void TempDataCookieNotFound(ILogger logger, string cookieName); + + [LoggerMessage(2, LogLevel.Debug, "The temp data cookie {CookieName} was used to successfully load temp data.", EventName = "TempDataCookieLoadSuccess")] + public static partial void TempDataCookieLoadSuccess(ILogger logger, string cookieName); + + [LoggerMessage(3, LogLevel.Warning, "The temp data cookie {CookieName} could not be loaded.", EventName = "TempDataCookieLoadFailure")] + public static partial void TempDataCookieLoadFailure(ILogger logger, string cookieName, Exception exception); + } } diff --git a/src/Mvc/Mvc.ViewFeatures/src/Filters/ValidateAntiforgeryTokenAuthorizationFilter.cs b/src/Mvc/Mvc.ViewFeatures/src/Filters/ValidateAntiforgeryTokenAuthorizationFilter.cs index f5816b221dda..15095473dcfb 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/Filters/ValidateAntiforgeryTokenAuthorizationFilter.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/Filters/ValidateAntiforgeryTokenAuthorizationFilter.cs @@ -7,7 +7,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Filters; -internal class ValidateAntiforgeryTokenAuthorizationFilter : IAsyncAuthorizationFilter, IAntiforgeryPolicy +internal partial class ValidateAntiforgeryTokenAuthorizationFilter : IAsyncAuthorizationFilter, IAntiforgeryPolicy { private readonly IAntiforgery _antiforgery; private readonly ILogger _logger; @@ -32,7 +32,7 @@ public async Task OnAuthorizationAsync(AuthorizationFilterContext context) if (!context.IsEffectivePolicy(this)) { - _logger.NotMostEffectiveFilter(typeof(IAntiforgeryPolicy)); + Log.NotMostEffectiveFilter(_logger, typeof(IAntiforgeryPolicy)); return; } @@ -44,7 +44,7 @@ public async Task OnAuthorizationAsync(AuthorizationFilterContext context) } catch (AntiforgeryValidationException exception) { - _logger.AntiforgeryTokenInvalid(exception.Message, exception); + Log.AntiforgeryTokenInvalid(_logger, exception.Message, exception); context.Result = new AntiforgeryValidationFailedResult(); } } @@ -59,4 +59,13 @@ protected virtual bool ShouldValidate(AuthorizationFilterContext context) return true; } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Information, "Antiforgery token validation failed. {Message}", EventName = "AntiforgeryTokenInvalid")] + public static partial void AntiforgeryTokenInvalid(ILogger logger, string message, Exception exception); + + [LoggerMessage(2, LogLevel.Trace, "Skipping the execution of current filter as its not the most effective filter implementing the policy {FilterPolicy}.", EventName = "NotMostEffectiveFilter")] + public static partial void NotMostEffectiveFilter(ILogger logger, Type filterPolicy); + } } diff --git a/src/Mvc/Mvc.ViewFeatures/src/MvcViewFeaturesLoggerExtensions.cs b/src/Mvc/Mvc.ViewFeatures/src/MvcViewFeaturesLoggerExtensions.cs deleted file mode 100644 index 82fe74dae614..000000000000 --- a/src/Mvc/Mvc.ViewFeatures/src/MvcViewFeaturesLoggerExtensions.cs +++ /dev/null @@ -1,312 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections; -using System.Globalization; -using Microsoft.AspNetCore.Mvc.ViewComponents; -using Microsoft.AspNetCore.Mvc.ViewEngines; -using Microsoft.Extensions.Logging; - -namespace Microsoft.AspNetCore.Mvc.ViewFeatures; - -internal static class MvcViewFeaturesLoggerExtensions -{ - private static readonly Action _viewComponentExecuting; - private static readonly Action _viewComponentExecuted; - - private static readonly Action _partialViewFound; - private static readonly Action, Exception> _partialViewNotFound; - private static readonly Action _partialViewResultExecuting; - private static readonly Action _partialViewResultExecuted; - - private static readonly Action _antiforgeryTokenInvalid; - - private static readonly Action _viewComponentResultExecuting; - - private static readonly Action _viewResultExecuting; - private static readonly Action _viewResultExecuted; - private static readonly Action _viewFound; - private static readonly Action, Exception> _viewNotFound; - - private static readonly Action _tempDataCookieNotFound; - private static readonly Action _tempDataCookieLoadSuccess; - private static readonly Action _tempDataCookieLoadFailure; - - private static readonly Action _notMostEffectiveFilter; - - private static readonly LogDefineOptions SkipEnabledCheckLogOptions = new() { SkipEnabledCheck = true }; - - static MvcViewFeaturesLoggerExtensions() - { - _viewComponentExecuting = LoggerMessage.Define( - LogLevel.Debug, - new EventId(1, "ViewComponentExecuting"), - "Executing view component {ViewComponentName} with arguments ({Arguments}).", - SkipEnabledCheckLogOptions); - - _viewComponentExecuted = LoggerMessage.Define( - LogLevel.Debug, - new EventId(2, "ViewComponentExecuted"), - "Executed view component {ViewComponentName} in {ElapsedMilliseconds}ms and returned " + - "{ViewComponentResult}", - SkipEnabledCheckLogOptions); - - _partialViewResultExecuting = LoggerMessage.Define( - LogLevel.Information, - new EventId(1, "PartialViewResultExecuting"), - "Executing PartialViewResult, running view {PartialViewName}."); - - _partialViewFound = LoggerMessage.Define( - LogLevel.Debug, - new EventId(2, "PartialViewFound"), - "The partial view path '{PartialViewFilePath}' was found in {ElapsedMilliseconds}ms."); - - _partialViewNotFound = LoggerMessage.Define>( - LogLevel.Error, - new EventId(3, "PartialViewNotFound"), - "The partial view '{PartialViewName}' was not found. Searched locations: {SearchedViewLocations}"); - - _partialViewResultExecuted = LoggerMessage.Define( - LogLevel.Information, - new EventId(4, "PartialViewResultExecuted"), - "Executed PartialViewResult - view {PartialViewName} executed in {ElapsedMilliseconds}ms."); - - _antiforgeryTokenInvalid = LoggerMessage.Define( - LogLevel.Information, - new EventId(1, "AntiforgeryTokenInvalid"), - "Antiforgery token validation failed. {Message}"); - - _viewComponentResultExecuting = LoggerMessage.Define( - LogLevel.Information, - new EventId(1, "ViewComponentResultExecuting"), - "Executing ViewComponentResult, running {ViewComponentName}.", - SkipEnabledCheckLogOptions); - - _viewResultExecuting = LoggerMessage.Define( - LogLevel.Information, - new EventId(1, "ViewResultExecuting"), - "Executing ViewResult, running view {ViewName}."); - - _viewFound = LoggerMessage.Define( - LogLevel.Debug, - new EventId(2, "ViewFound"), - "The view path '{ViewFilePath}' was found in {ElapsedMilliseconds}ms."); - - _viewNotFound = LoggerMessage.Define>( - LogLevel.Error, - new EventId(3, "ViewNotFound"), - "The view '{ViewName}' was not found. Searched locations: {SearchedViewLocations}"); - - _viewResultExecuted = LoggerMessage.Define( - LogLevel.Information, - new EventId(4, "ViewResultExecuted"), - "Executed ViewResult - view {ViewName} executed in {ElapsedMilliseconds}ms."); - - _tempDataCookieNotFound = LoggerMessage.Define( - LogLevel.Debug, - new EventId(1, "TempDataCookieNotFound"), - "The temp data cookie {CookieName} was not found."); - - _tempDataCookieLoadSuccess = LoggerMessage.Define( - LogLevel.Debug, - new EventId(2, "TempDataCookieLoadSuccess"), - "The temp data cookie {CookieName} was used to successfully load temp data."); - - _tempDataCookieLoadFailure = LoggerMessage.Define( - LogLevel.Warning, - new EventId(3, "TempDataCookieLoadFailure"), - "The temp data cookie {CookieName} could not be loaded."); - - _notMostEffectiveFilter = LoggerMessage.Define( - LogLevel.Trace, - new EventId(1, "NotMostEffectiveFilter"), - "Skipping the execution of current filter as its not the most effective filter implementing the policy {FilterPolicy}."); - } - -#nullable enable - public static IDisposable? ViewComponentScope(this ILogger logger, ViewComponentContext context) - { - return logger.BeginScope(new ViewComponentLogScope(context.ViewComponentDescriptor)); - } -#nullable restore - - public static void ViewComponentExecuting( - this ILogger logger, - ViewComponentContext context, - object[] arguments) - { - if (logger.IsEnabled(LogLevel.Debug)) - { - var formattedArguments = GetFormattedArguments(arguments); - _viewComponentExecuting(logger, context.ViewComponentDescriptor.DisplayName, formattedArguments, null); - } - } - - private static string[] GetFormattedArguments(object[] arguments) - { - if (arguments == null || arguments.Length == 0) - { - return Array.Empty(); - } - - var formattedArguments = new string[arguments.Length]; - for (var i = 0; i < formattedArguments.Length; i++) - { - formattedArguments[i] = Convert.ToString(arguments[i], CultureInfo.InvariantCulture); - } - - return formattedArguments; - } - - public static void ViewComponentExecuted( - this ILogger logger, - ViewComponentContext context, - TimeSpan timespan, - object result) - { - // Don't log if logging wasn't enabled at start of request as time will be wildly wrong. - if (logger.IsEnabled(LogLevel.Debug)) - { - _viewComponentExecuted( - logger, - context.ViewComponentDescriptor.DisplayName, - timespan.TotalMilliseconds, - Convert.ToString(result, CultureInfo.InvariantCulture), - null); - } - } - - public static void PartialViewFound( - this ILogger logger, - IView view, - TimeSpan timespan) - { - _partialViewFound(logger, view.Path, timespan.TotalMilliseconds, null); - } - - public static void PartialViewNotFound( - this ILogger logger, - string partialViewName, - IEnumerable searchedLocations) - { - _partialViewNotFound(logger, partialViewName, searchedLocations, null); - } - - public static void PartialViewResultExecuting(this ILogger logger, string partialViewName) - { - _partialViewResultExecuting(logger, partialViewName, null); - } - - public static void PartialViewResultExecuted(this ILogger logger, string partialViewName, TimeSpan timespan) - { - _partialViewResultExecuted(logger, partialViewName, timespan.TotalMilliseconds, null); - } - - public static void AntiforgeryTokenInvalid(this ILogger logger, string message, Exception exception) - { - _antiforgeryTokenInvalid(logger, message, exception); - } - - public static void ViewComponentResultExecuting(this ILogger logger, string viewComponentName) - { - if (logger.IsEnabled(LogLevel.Information)) - { - _viewComponentResultExecuting(logger, viewComponentName, null); - } - } - - public static void ViewComponentResultExecuting(this ILogger logger, Type viewComponentType) - { - if (logger.IsEnabled(LogLevel.Information)) - { - _viewComponentResultExecuting(logger, viewComponentType.Name, null); - } - } - - public static void ViewResultExecuting(this ILogger logger, string viewName) - { - _viewResultExecuting(logger, viewName, null); - } - - public static void ViewResultExecuted(this ILogger logger, string viewName, TimeSpan timespan) - { - _viewResultExecuted(logger, viewName, timespan.TotalMilliseconds, null); - } - - public static void ViewFound(this ILogger logger, IView view, TimeSpan timespan) - { - _viewFound(logger, view.Path, timespan.TotalMilliseconds, null); - } - - public static void ViewNotFound(this ILogger logger, string viewName, - IEnumerable searchedLocations) - { - _viewNotFound(logger, viewName, searchedLocations, null); - } - - public static void TempDataCookieNotFound(this ILogger logger, string cookieName) - { - _tempDataCookieNotFound(logger, cookieName, null); - } - - public static void TempDataCookieLoadSuccess(this ILogger logger, string cookieName) - { - _tempDataCookieLoadSuccess(logger, cookieName, null); - } - - public static void TempDataCookieLoadFailure(this ILogger logger, string cookieName, Exception exception) - { - _tempDataCookieLoadFailure(logger, cookieName, exception); - } - - public static void NotMostEffectiveFilter(this ILogger logger, Type policyType) - { - _notMostEffectiveFilter(logger, policyType, null); - } - - private class ViewComponentLogScope : IReadOnlyList> - { - private readonly ViewComponentDescriptor _descriptor; - - public ViewComponentLogScope(ViewComponentDescriptor descriptor) - { - _descriptor = descriptor; - } - - public KeyValuePair this[int index] - { - get - { - if (index == 0) - { - return new KeyValuePair("ViewComponentName", _descriptor.DisplayName); - } - else if (index == 1) - { - return new KeyValuePair("ViewComponentId", _descriptor.Id); - } - throw new IndexOutOfRangeException(nameof(index)); - } - } - - public int Count => 2; - - public IEnumerator> GetEnumerator() - { - for (var i = 0; i < Count; ++i) - { - yield return this[i]; - } - } - - public override string ToString() - { - return _descriptor.DisplayName; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} diff --git a/src/Mvc/Mvc.ViewFeatures/src/PartialViewResultExecutor.cs b/src/Mvc/Mvc.ViewFeatures/src/PartialViewResultExecutor.cs index 3904f4cc0c5e..4a05f8281694 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/PartialViewResultExecutor.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/PartialViewResultExecutor.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures; /// /// Finds and executes an for a . /// -public class PartialViewResultExecutor : ViewExecutor, IActionResultExecutor +public partial class PartialViewResultExecutor : ViewExecutor, IActionResultExecutor { private const string ActionNameKey = "action"; @@ -85,7 +85,7 @@ public virtual ViewEngineResult FindView(ActionContext actionContext, PartialVie result = viewEngine.FindView(actionContext, viewName, isMainPage: false); } - Logger.PartialViewResultExecuting(result.ViewName); + Log.PartialViewResultExecuting(Logger, result.ViewName); if (!result.Success) { if (originalResult.SearchedLocations.Any()) @@ -113,8 +113,7 @@ public virtual ViewEngineResult FindView(ActionContext actionContext, PartialVie viewResult: viewResult, viewName: viewName, view: result.View); - - Logger.PartialViewFound(result.View, stopwatch.GetElapsedTime()); + Log.PartialViewFound(Logger, result.View, stopwatch.GetElapsedTime()); } else { @@ -124,8 +123,7 @@ public virtual ViewEngineResult FindView(ActionContext actionContext, PartialVie viewResult: viewResult, viewName: viewName, searchedLocations: result.SearchedLocations); - - Logger.PartialViewNotFound(viewName, result.SearchedLocations); + Log.PartialViewNotFound(Logger, viewName, result.SearchedLocations); } return result; @@ -188,7 +186,7 @@ public virtual async Task ExecuteAsync(ActionContext context, PartialViewResult await ExecuteAsync(context, view, result); } - Logger.PartialViewResultExecuted(result.ViewName, stopwatch.GetElapsedTime()); + Log.PartialViewResultExecuted(Logger, result.ViewName, stopwatch.GetElapsedTime()); } private static string? GetActionName(ActionContext context) @@ -219,4 +217,29 @@ public virtual async Task ExecuteAsync(ActionContext context, PartialViewResult return stringRouteValue; } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Information, "Executing PartialViewResult, running view {PartialViewName}.", EventName = "PartialViewResultExecuting")] + public static partial void PartialViewResultExecuting(ILogger logger, string partialViewName); + + [LoggerMessage(2, LogLevel.Debug, "The partial view path '{PartialViewFilePath}' was found in {ElapsedMilliseconds}ms.", EventName = "PartialViewFound")] + private static partial void PartialViewFound(ILogger logger, string partialViewFilePath, double elapsedMilliseconds); + + public static void PartialViewFound(ILogger logger, IView view, TimeSpan timespan) + { + PartialViewFound(logger, view.Path, timespan.TotalMilliseconds); + } + + [LoggerMessage(3, LogLevel.Error, "The partial view '{PartialViewName}' was not found. Searched locations: {SearchedViewLocations}", EventName = "PartialViewNotFound")] + public static partial void PartialViewNotFound(ILogger logger, string partialViewName, IEnumerable searchedViewLocations); + + [LoggerMessage(4, LogLevel.Information, "Executed PartialViewResult - view {PartialViewName} executed in {ElapsedMilliseconds}ms.", EventName = "PartialViewResultExecuted")] + private static partial void PartialViewResultExecuted(ILogger logger, string? partialViewName, double elapsedMilliseconds); + + public static void PartialViewResultExecuted(ILogger logger, string? partialViewName, TimeSpan timespan) + { + PartialViewResultExecuted(logger, partialViewName, timespan.TotalMilliseconds); + } + } } diff --git a/src/Mvc/Mvc.ViewFeatures/src/ViewComponentResultExecutor.cs b/src/Mvc/Mvc.ViewFeatures/src/ViewComponentResultExecutor.cs index 33ed8798f0ae..54195048895b 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/ViewComponentResultExecutor.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/ViewComponentResultExecutor.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures; /// /// A for . /// -public class ViewComponentResultExecutor : IActionResultExecutor +public partial class ViewComponentResultExecutor : IActionResultExecutor { private readonly HtmlEncoder _htmlEncoder; private readonly HtmlHelperOptions _htmlHelperOptions; @@ -178,13 +178,24 @@ private static Task GetViewComponentResult(IViewComponentHelper vi } else if (result.ViewComponentType == null) { - logger.ViewComponentResultExecuting(result.ViewComponentName); + Log.ViewComponentResultExecuting(logger, result.ViewComponentName); return viewComponentHelper.InvokeAsync(result.ViewComponentName!, result.Arguments); } else { - logger.ViewComponentResultExecuting(result.ViewComponentType); + Log.ViewComponentResultExecuting(_logger, result.ViewComponentType); return viewComponentHelper.InvokeAsync(result.ViewComponentType, result.Arguments); } } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Information, "Executing ViewComponentResult, running {ViewComponentName}.", EventName = "ViewComponentResultExecuting")] + public static partial void ViewComponentResultExecuting(ILogger logger, string? viewComponentName); + + public static void ViewComponentResultExecuting(ILogger logger, Type viewComponentType) + { + ViewComponentResultExecuting(logger, viewComponentType.Name); + } + } } diff --git a/src/Mvc/Mvc.ViewFeatures/src/ViewComponents/DefaultViewComponentInvoker.cs b/src/Mvc/Mvc.ViewFeatures/src/ViewComponents/DefaultViewComponentInvoker.cs index cd0b2df7e4ef..e48ed6a820d0 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/ViewComponents/DefaultViewComponentInvoker.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/ViewComponents/DefaultViewComponentInvoker.cs @@ -3,7 +3,9 @@ #nullable enable +using System.Collections; using System.Diagnostics; +using System.Globalization; using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.Extensions.Internal; @@ -14,7 +16,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewComponents; /// /// Default implementation for . /// -internal class DefaultViewComponentInvoker : IViewComponentInvoker +internal partial class DefaultViewComponentInvoker : IViewComponentInvoker { private readonly IViewComponentFactory _viewComponentFactory; private readonly ViewComponentInvokerCache _viewComponentInvokerCache; @@ -106,12 +108,12 @@ public async Task InvokeAsync(ViewComponentContext context) private async Task InvokeAsyncCore(ObjectMethodExecutor executor, object component, ViewComponentContext context) { - using (_logger.ViewComponentScope(context)) + using (Log.ViewComponentScope(_logger, context)) { var arguments = PrepareArguments(context.Arguments, executor); _diagnosticListener.BeforeViewComponent(context, component); - _logger.ViewComponentExecuting(context, arguments); + Log.ViewComponentExecuting(_logger, context, arguments); var stopwatch = ValueStopwatch.StartNew(); @@ -154,7 +156,7 @@ private async Task InvokeAsyncCore(ObjectMethodExecutor ex } var viewComponentResult = CoerceToViewComponentResult(resultAsObject); - _logger.ViewComponentExecuted(context, stopwatch.GetElapsedTime(), viewComponentResult); + Log.ViewComponentExecuted(_logger, context, stopwatch.GetElapsedTime(), viewComponentResult); _diagnosticListener.AfterViewComponent(context, viewComponentResult, component); return viewComponentResult; @@ -163,12 +165,12 @@ private async Task InvokeAsyncCore(ObjectMethodExecutor ex private IViewComponentResult InvokeSyncCore(ObjectMethodExecutor executor, object component, ViewComponentContext context) { - using (_logger.ViewComponentScope(context)) + using (Log.ViewComponentScope(_logger, context)) { var arguments = PrepareArguments(context.Arguments, executor); _diagnosticListener.BeforeViewComponent(context, component); - _logger.ViewComponentExecuting(context, arguments); + Log.ViewComponentExecuting(_logger, context, arguments); var stopwatch = ValueStopwatch.StartNew(); object? result; @@ -176,7 +178,7 @@ private IViewComponentResult InvokeSyncCore(ObjectMethodExecutor executor, objec result = executor.Execute(component, arguments); var viewComponentResult = CoerceToViewComponentResult(result); - _logger.ViewComponentExecuted(context, stopwatch.GetElapsedTime(), viewComponentResult); + Log.ViewComponentExecuted(_logger, context, stopwatch.GetElapsedTime(), viewComponentResult); _diagnosticListener.AfterViewComponent(context, viewComponentResult, component); return viewComponentResult; @@ -237,4 +239,110 @@ private static IViewComponentResult CoerceToViewComponentResult(object? value) return arguments; } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Debug, "Executing view component {ViewComponentName} with arguments ({Arguments}).", EventName = "ViewComponentExecuting", SkipEnabledCheck = true)] + private static partial void ViewComponentExecuting(ILogger logger, string viewComponentName, string[] arguments); + + [LoggerMessage(2, LogLevel.Debug, "Executed view component {ViewComponentName} in {ElapsedMilliseconds}ms and returned {ViewComponentResult}", EventName = "ViewComponentExecuted", SkipEnabledCheck = true)] + private static partial void ViewComponentExecuted(ILogger logger, string viewComponentName, double elapsedMilliseconds, string? viewComponentResult); + + public static IDisposable? ViewComponentScope(ILogger logger, ViewComponentContext context) + { + return logger.BeginScope(new ViewComponentLogScope(context.ViewComponentDescriptor)); + } + +#nullable restore + public static void ViewComponentExecuting( + ILogger logger, + ViewComponentContext context, + object[] arguments) + { + if (logger.IsEnabled(LogLevel.Debug)) + { + var formattedArguments = GetFormattedArguments(arguments); + ViewComponentExecuting(logger, context.ViewComponentDescriptor.DisplayName, formattedArguments); + } + } + + public static void ViewComponentExecuted( + ILogger logger, + ViewComponentContext context, + TimeSpan timespan, + object result) + { + // Don't log if logging wasn't enabled at start of request as time will be wildly wrong. + if (logger.IsEnabled(LogLevel.Debug)) + { + ViewComponentExecuted( + logger, + context.ViewComponentDescriptor.DisplayName, + timespan.TotalMilliseconds, + Convert.ToString(result, CultureInfo.InvariantCulture)); + } + } + + private static string[] GetFormattedArguments(object[] arguments) + { + if (arguments == null || arguments.Length == 0) + { + return Array.Empty(); + } + + var formattedArguments = new string[arguments.Length]; + for (var i = 0; i < formattedArguments.Length; i++) + { + formattedArguments[i] = Convert.ToString(arguments[i], CultureInfo.InvariantCulture); + } + + return formattedArguments; + } + + private sealed class ViewComponentLogScope : IReadOnlyList> + { + private readonly ViewComponentDescriptor _descriptor; + + public ViewComponentLogScope(ViewComponentDescriptor descriptor) + { + _descriptor = descriptor; + } + + public KeyValuePair this[int index] + { + get + { + if (index == 0) + { + return new KeyValuePair("ViewComponentName", _descriptor.DisplayName); + } + else if (index == 1) + { + return new KeyValuePair("ViewComponentId", _descriptor.Id); + } + throw new IndexOutOfRangeException(nameof(index)); + } + } + + public int Count => 2; + + public IEnumerator> GetEnumerator() + { + for (var i = 0; i < Count; ++i) + { + yield return this[i]; + } + } + + public override string ToString() + { + return _descriptor.DisplayName; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + } } diff --git a/src/Mvc/Mvc.ViewFeatures/src/ViewResultExecutor.cs b/src/Mvc/Mvc.ViewFeatures/src/ViewResultExecutor.cs index 0db47f1b1e6a..bde2700da584 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/ViewResultExecutor.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/ViewResultExecutor.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures; /// /// Finds and executes an for a . /// -public class ViewResultExecutor : ViewExecutor, IActionResultExecutor +public partial class ViewResultExecutor : ViewExecutor, IActionResultExecutor { private const string ActionNameKey = "action"; @@ -86,7 +86,7 @@ public virtual ViewEngineResult FindView(ActionContext actionContext, ViewResult result = viewEngine.FindView(actionContext, viewName, isMainPage: true); } - Logger.ViewResultExecuting(result.ViewName); + Log.ViewResultExecuting(Logger, result.ViewName); if (!result.Success) { if (originalResult.SearchedLocations.Any()) @@ -113,11 +113,11 @@ public virtual ViewEngineResult FindView(ActionContext actionContext, ViewResult if (result.Success) { - Logger.ViewFound(result.View, stopwatch.GetElapsedTime()); + Log.ViewFound(Logger, result.View, stopwatch.GetElapsedTime()); } else { - Logger.ViewNotFound(viewName, result.SearchedLocations); + Log.ViewNotFound(Logger, viewName, result.SearchedLocations); } return result; @@ -175,7 +175,7 @@ await ExecuteAsync( result.StatusCode); } - Logger.ViewResultExecuted(viewEngineResult.ViewName, stopwatch.GetElapsedTime()); + Log.ViewResultExecuted(Logger, viewEngineResult.ViewName, stopwatch.GetElapsedTime()); } private static string? GetActionName(ActionContext context) @@ -206,4 +206,29 @@ await ExecuteAsync( return stringRouteValue; } + + private static partial class Log + { + [LoggerMessage(1, LogLevel.Information, "Executing ViewResult, running view {ViewName}.", EventName = "ViewResultExecuting")] + public static partial void ViewResultExecuting(ILogger logger, string viewName); + + [LoggerMessage(2, LogLevel.Debug, "The view path '{ViewFilePath}' was found in {ElapsedMilliseconds}ms.", EventName = "ViewFound")] + private static partial void ViewFound(ILogger logger, string viewFilePath, double elapsedMilliseconds); + + public static void ViewFound(ILogger logger, IView view, TimeSpan timespan) + { + ViewFound(logger, view.Path, timespan.TotalMilliseconds); + } + + [LoggerMessage(3, LogLevel.Error, "The view '{ViewName}' was not found. Searched locations: {SearchedViewLocations}", EventName = "ViewNotFound")] + public static partial void ViewNotFound(ILogger logger, string viewName, IEnumerable searchedViewLocations); + + [LoggerMessage(4, LogLevel.Information, "Executed ViewResult - view {ViewName} executed in {ElapsedMilliseconds}ms.", EventName = "ViewResultExecuted")] + private static partial void ViewResultExecuted(ILogger logger, string viewName, double elapsedMilliseconds); + + public static void ViewResultExecuted(ILogger logger, string viewName, TimeSpan timespan) + { + ViewResultExecuted(logger, viewName, timespan.TotalMilliseconds); + } + } }