diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ControllerBase.cs b/src/Microsoft.AspNetCore.Mvc.Core/ControllerBase.cs index 3fc8c444e4..9ca57bdc2f 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ControllerBase.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ControllerBase.cs @@ -1551,7 +1551,7 @@ namespace Microsoft.AspNetCore.Mvc /// This supports range requests ( or /// if the range is not satisfiable). /// - /// The physical path of the file to be returned. + /// The path to the file. The path must be an absolute path. /// The Content-Type of the file. /// The created for the response. [NonAction] @@ -1564,7 +1564,7 @@ namespace Microsoft.AspNetCore.Mvc /// This supports range requests ( or /// if the range is not satisfiable). /// - /// The physical path of the file to be returned. + /// The path to the file. The path must be an absolute path. /// The Content-Type of the file. /// Set to true to enable range requests processing. /// The created for the response. @@ -1579,7 +1579,7 @@ namespace Microsoft.AspNetCore.Mvc /// This supports range requests ( or /// if the range is not satisfiable). /// - /// The physical path of the file to be returned. + /// The path to the file. The path must be an absolute path. /// The Content-Type of the file. /// The suggested file name. /// The created for the response. @@ -1597,7 +1597,7 @@ namespace Microsoft.AspNetCore.Mvc /// This supports range requests ( or /// if the range is not satisfiable). /// - /// The physical path of the file to be returned. + /// The path to the file. The path must be an absolute path. /// The Content-Type of the file. /// The suggested file name. /// Set to true to enable range requests processing. @@ -1620,7 +1620,7 @@ namespace Microsoft.AspNetCore.Mvc /// This supports range requests ( or /// if the range is not satisfiable). /// - /// The physical path of the file to be returned. + /// The path to the file. The path must be an absolute path. /// The Content-Type of the file. /// The of when the file was last modified. /// The associated with the file. @@ -1641,7 +1641,7 @@ namespace Microsoft.AspNetCore.Mvc /// This supports range requests ( or /// if the range is not satisfiable). /// - /// The physical path of the file to be returned. + /// The path to the file. The path must be an absolute path. /// The Content-Type of the file. /// The of when the file was last modified. /// The associated with the file. @@ -1664,7 +1664,7 @@ namespace Microsoft.AspNetCore.Mvc /// This supports range requests ( or /// if the range is not satisfiable). /// - /// The physical path of the file to be returned. + /// The path to the file. The path must be an absolute path. /// The Content-Type of the file. /// The suggested file name. /// The of when the file was last modified. @@ -1687,7 +1687,7 @@ namespace Microsoft.AspNetCore.Mvc /// This supports range requests ( or /// if the range is not satisfiable). /// - /// The physical path of the file to be returned. + /// The path to the file. The path must be an absolute path. /// The Content-Type of the file. /// The suggested file name. /// The of when the file was last modified. diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileContentResultExecutor.cs b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileContentResultExecutor.cs index 0739c522d4..6d194c52f8 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileContentResultExecutor.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileContentResultExecutor.cs @@ -4,6 +4,7 @@ using System; using System.IO; using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; @@ -29,6 +30,8 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure throw new ArgumentNullException(nameof(result)); } + Logger.ExecutingFileResult(result); + var (range, rangeLength, serveBody) = SetHeadersAndLog( context, result, @@ -62,6 +65,11 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure return Task.CompletedTask; } + if (range != null) + { + Logger.WritingRangeToBody(); + } + var fileContentStream = new MemoryStream(result.FileContents); return WriteFileAsync(context.HttpContext, fileContentStream, range, rangeLength); } diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileResultExecutorBase.cs b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileResultExecutorBase.cs index 6bd8939bc7..19e5b8d6c7 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileResultExecutorBase.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileResultExecutorBase.cs @@ -56,7 +56,6 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure SetContentType(context, result); SetContentDispositionHeader(context, result); - Logger.FileResultExecuting(result.FileDownloadName); var request = context.HttpContext.Request; var httpRequestHeaders = request.GetTypedHeaders(); @@ -106,6 +105,10 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure return SetRangeHeaders(context, httpRequestHeaders, fileLength.Value); } } + else + { + Logger.NotEnabledForRangeProcessing(); + } } return (range: null, rangeLength: 0, serveBody); @@ -150,7 +153,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure response.Headers[HeaderNames.AcceptRanges] = AcceptRangeHeaderValue; } - internal static bool IfRangeValid( + internal bool IfRangeValid( RequestHeaders httpRequestHeaders, DateTimeOffset? lastModified = null, EntityTagHeaderValue etag = null) @@ -168,11 +171,13 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure { if (lastModified.HasValue && lastModified > ifRange.LastModified) { + Logger.IfRangeLastModifiedPreconditionFailed(lastModified, ifRange.LastModified); return false; } } else if (etag != null && ifRange.EntityTag != null && !ifRange.EntityTag.Compare(etag, useStrongComparison: true)) { + Logger.IfRangeETagPreconditionFailed(etag, ifRange.EntityTag); return false; } } @@ -181,7 +186,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure } // Internal for testing - internal static PreconditionState GetPreconditionState( + internal PreconditionState GetPreconditionState( RequestHeaders httpRequestHeaders, DateTimeOffset? lastModified = null, EntityTagHeaderValue etag = null) @@ -200,6 +205,11 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure etag: etag, matchFoundState: PreconditionState.ShouldProcess, matchNotFoundState: PreconditionState.PreconditionFailed); + + if (ifMatchState == PreconditionState.PreconditionFailed) + { + Logger.IfMatchPreconditionFailed(etag); + } } // 14.26 If-None-Match @@ -229,6 +239,11 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure { var unmodified = ifUnmodifiedSince >= lastModified; ifUnmodifiedSinceState = unmodified ? PreconditionState.ShouldProcess : PreconditionState.PreconditionFailed; + + if (ifUnmodifiedSinceState == PreconditionState.PreconditionFailed) + { + Logger.IfUnmodifiedSincePreconditionFailed(lastModified, ifUnmodifiedSince); + } } var state = GetMaxPreconditionState(ifMatchState, ifNoneMatchState, ifModifiedSinceState, ifUnmodifiedSinceState); @@ -273,7 +288,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure return max; } - private static (RangeItemHeaderValue range, long rangeLength, bool serveBody) SetRangeHeaders( + private (RangeItemHeaderValue range, long rangeLength, bool serveBody) SetRangeHeaders( ActionContext context, RequestHeaders httpRequestHeaders, long fileLength) @@ -286,7 +301,8 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure var (isRangeRequest, range) = RangeHelper.ParseRange( context.HttpContext, httpRequestHeaders, - fileLength); + fileLength, + Logger); if (!isRangeRequest) { diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileStreamResultExecutor.cs b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileStreamResultExecutor.cs index 72a4d53cb5..46e10e036c 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileStreamResultExecutor.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/FileStreamResultExecutor.cs @@ -3,6 +3,7 @@ using System; using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; @@ -28,6 +29,8 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure throw new ArgumentNullException(nameof(result)); } + Logger.ExecutingFileResult(result); + long? fileLength = null; if (result.FileStream.CanSeek) { @@ -67,6 +70,11 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure return Task.CompletedTask; } + if (range != null) + { + Logger.WritingRangeToBody(); + } + return WriteFileAsync(context.HttpContext, result.FileStream, range, rangeLength); } } diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/PhysicalFileResultExecutor.cs b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/PhysicalFileResultExecutor.cs index e36d22a3d9..fa4757212d 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/PhysicalFileResultExecutor.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/PhysicalFileResultExecutor.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Mvc.Core; +using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; @@ -39,6 +40,8 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure Resources.FormatFileResult_InvalidPath(result.FileName), result.FileName); } + Logger.ExecutingFileResult(result, result.FileName); + var lastModified = result.LastModified ?? fileInfo.LastModified; var (range, rangeLength, serveBody) = SetHeadersAndLog( context, @@ -79,6 +82,11 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure throw new NotSupportedException(Resources.FormatFileResult_PathNotRooted(result.FileName)); } + if (range != null) + { + Logger.WritingRangeToBody(); + } + var sendFile = response.HttpContext.Features.Get(); if (sendFile != null) { diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/VirtualFileResultExecutor.cs b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/VirtualFileResultExecutor.cs index 42b0b2a669..d9702a572f 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/VirtualFileResultExecutor.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Infrastructure/VirtualFileResultExecutor.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Mvc.Core; +using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; @@ -49,6 +50,8 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure Resources.FormatFileResult_InvalidPath(result.FileName), result.FileName); } + Logger.ExecutingFileResult(result, result.FileName); + var lastModified = result.LastModified ?? fileInfo.LastModified; var (range, rangeLength, serveBody) = SetHeadersAndLog( context, @@ -85,6 +88,12 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure var response = context.HttpContext.Response; var physicalPath = fileInfo.PhysicalPath; + + if (range != null) + { + Logger.WritingRangeToBody(); + } + var sendFile = response.HttpContext.Features.Get(); if (sendFile != null && !string.IsNullOrEmpty(physicalPath)) { @@ -110,6 +119,10 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure private IFileInfo GetFileInformation(VirtualFileResult result) { var fileProvider = GetFileProvider(result); + if (fileProvider is NullFileProvider) + { + throw new InvalidOperationException(Resources.VirtualFileResultExecutor_NoFileProviderConfigured); + } var normalizedPath = result.FileName; if (normalizedPath.StartsWith("~", StringComparison.Ordinal)) diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcCoreLoggerExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcCoreLoggerExtensions.cs index ed5e2354e7..4cc0f8f900 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcCoreLoggerExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcCoreLoggerExtensions.cs @@ -16,6 +16,7 @@ using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.AspNetCore.Mvc.Formatters.Internal; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.Extensions.Logging; +using Microsoft.Net.Http.Headers; namespace Microsoft.AspNetCore.Mvc.Internal { @@ -45,8 +46,10 @@ namespace Microsoft.AspNetCore.Mvc.Internal private static readonly Action _ambiguousActions; private static readonly Action _constraintMismatch; - private static readonly Action _fileResultExecuting; - + 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; @@ -101,6 +104,10 @@ namespace Microsoft.AspNetCore.Mvc.Internal 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; @@ -175,10 +182,15 @@ namespace Microsoft.AspNetCore.Mvc.Internal 2, "Action '{ActionName}' with id '{ActionId}' did not match the constraint '{ActionConstraint}'"); - _fileResultExecuting = LoggerMessage.Define( + _executingFileResult = LoggerMessage.Define( LogLevel.Information, 1, - "Executing FileResult, sending file as {FileDownloadName}"); + "Executing {FileResultType}, sending file '{FileDownloadPath}' with download name '{FileDownloadName}' ..."); + + _executingFileResultWithNoFileName = LoggerMessage.Define( + LogLevel.Information, + 2, + "Executing {FileResultType}, sending file with download name '{FileDownloadName}' ..."); _authorizationFailure = LoggerMessage.Define( LogLevel.Information, @@ -404,6 +416,36 @@ namespace Microsoft.AspNetCore.Mvc.Internal LogLevel.Debug, 11, "List of registered output formatters, in the following order: {OutputFormatters}"); + + _ifMatchPreconditionFailed = LoggerMessage.Define( + LogLevel.Debug, + 12, + "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, + 13, + "Current request's If-Unmodified-Since header check failed as the file was modified (at '{lastModified}') after the If-Unmodified-Since date '{IfUnmodifiedSinceDate}'."); + + _ifRangeLastModifiedPreconditionFailed = LoggerMessage.Define( + LogLevel.Debug, + 14, + "Could not serve range as the file was modified (at {LastModified}) after the if-Range's last modified date '{IfRangeLastModified}'."); + + _ifRangeETagPreconditionFailed = LoggerMessage.Define( + LogLevel.Debug, + 15, + "Could not serve range as the file's current etag '{CurrentETag}' does not match the If-Range etag '{IfRangeETag}'."); + + _notEnabledForRangeProcessing = LoggerMessage.Define( + LogLevel.Debug, + 16, + $"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'."); + + _writingRangeToBody = LoggerMessage.Define( + LogLevel.Debug, + 17, + "Writing the requested range of bytes to the body..."); } public static void RegisteredOutputFormatters(this ILogger logger, IEnumerable outputFormatters) @@ -412,8 +454,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal } public static void SelectingOutputFormatterUsingAcceptHeaderAndExplicitContentTypes( - this ILogger logger, - IEnumerable acceptHeader, + this ILogger logger, + IEnumerable acceptHeader, MediaTypeCollection mediaTypeCollection) { _selectingOutputFormatterUsingAcceptHeaderAndExplicitContentTypes(logger, acceptHeader, mediaTypeCollection, null); @@ -624,9 +666,24 @@ namespace Microsoft.AspNetCore.Mvc.Internal _constraintMismatch(logger, actionName, actionId, actionConstraint, null); } - public static void FileResultExecuting(this ILogger logger, string fileDownloadName) + public static void ExecutingFileResult(this ILogger logger, FileResult fileResult) { - _fileResultExecuting(logger, fileDownloadName, null); + _executingFileResultWithNoFileName(logger, fileResult, fileResult.FileDownloadName, null); + } + + public static void ExecutingFileResult(this ILogger logger, FileResult fileResult, string fileName) + { + _executingFileResult(logger, fileResult, fileName, fileResult.FileDownloadName, null); + } + + public static void NotEnabledForRangeProcessing(this ILogger logger) + { + _notEnabledForRangeProcessing(logger, null); + } + + public static void WritingRangeToBody(this ILogger logger) + { + _writingRangeToBody(logger, null); } public static void AuthorizationFailure( @@ -881,6 +938,35 @@ namespace Microsoft.AspNetCore.Mvc.Internal } } + public static void IfMatchPreconditionFailed(this ILogger logger, EntityTagHeaderValue etag) + { + _ifMatchPreconditionFailed(logger, etag, null); + } + + public static void IfUnmodifiedSincePreconditionFailed( + this ILogger logger, + DateTimeOffset? lastModified, + DateTimeOffset? ifUnmodifiedSinceDate) + { + _ifUnmodifiedSincePreconditionFailed(logger, lastModified, ifUnmodifiedSinceDate, null); + } + + public static void IfRangeLastModifiedPreconditionFailed( + this ILogger logger, + DateTimeOffset? lastModified, + DateTimeOffset? ifRangeLastModifiedDate) + { + _ifRangeLastModifiedPreconditionFailed(logger, lastModified, ifRangeLastModifiedDate, null); + } + + public static void IfRangeETagPreconditionFailed( + this ILogger logger, + EntityTagHeaderValue currentETag, + EntityTagHeaderValue ifRangeTag) + { + _ifRangeETagPreconditionFailed(logger, currentETag, ifRangeTag, null); + } + private static void LogFilterExecutionPlan( ILogger logger, string filterType, diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs index 772a8977d3..443a6a59b1 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Properties/Resources.Designer.cs @@ -1354,6 +1354,20 @@ namespace Microsoft.AspNetCore.Mvc.Core internal static string FormatApiController_AttributeRouteRequired(object p0) => string.Format(CultureInfo.CurrentCulture, GetString("ApiController_AttributeRouteRequired"), p0); + /// + /// No file provider has been configured to process the supplied file. + /// + internal static string VirtualFileResultExecutor_NoFileProviderConfigured + { + get => GetString("VirtualFileResultExecutor_NoFileProviderConfigured"); + } + + /// + /// No file provider has been configured to process the supplied file. + /// + internal static string FormatVirtualFileResultExecutor_NoFileProviderConfigured() + => GetString("VirtualFileResultExecutor_NoFileProviderConfigured"); + private static string GetString(string name, params string[] formatterNames) { var value = _resourceManager.GetString(name); diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx b/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx index dce45c2f75..4a0fd9fd1a 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx +++ b/src/Microsoft.AspNetCore.Mvc.Core/Resources.resx @@ -418,4 +418,7 @@ Action methods on controllers annotated with {0} must have an attribute route. + + No file provider has been configured to process the supplied file. + \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/FileResultTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/FileResultTest.cs index 898d915fc2..366380abd5 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/FileResultTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/FileResultTest.cs @@ -142,28 +142,6 @@ namespace Microsoft.AspNetCore.Mvc await Assert.ThrowsAsync(() => result.ExecuteResultAsync(actionContext)); } - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.CLR, SkipReason = "Fails due to dotnet/standard#567")] - public async Task ExecuteResultAsync_LogsInformation_IfCanResolveLoggerFactory() - { - // Arrange - var httpContext = new DefaultHttpContext(); - var services = new ServiceCollection(); - var loggerSink = new TestSink(); - services.AddSingleton(new TestLoggerFactory(loggerSink, true)); - services.AddSingleton(); - httpContext.RequestServices = services.BuildServiceProvider(); - - var actionContext = CreateActionContext(httpContext); - var result = new EmptyFileResult("application/my-type"); - - // Act - await result.ExecuteResultAsync(actionContext); - - // Assert - Assert.Single(loggerSink.Writes); - } - public static TheoryData ContentDispositionData { get @@ -302,9 +280,10 @@ namespace Microsoft.AspNetCore.Mvc httpRequestHeaders.IfUnmodifiedSince = lastModified; httpRequestHeaders.IfModifiedSince = DateTimeOffset.MinValue.AddDays(1); actionContext.HttpContext = httpContext; + var fileResult = (new Mock(NullLogger.Instance)).Object; // Act - var state = FileResultExecutorBase.GetPreconditionState( + var state = fileResult.GetPreconditionState( httpRequestHeaders, lastModified, etag); @@ -338,9 +317,10 @@ namespace Microsoft.AspNetCore.Mvc httpRequestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue; httpRequestHeaders.IfModifiedSince = DateTimeOffset.MinValue.AddDays(2); actionContext.HttpContext = httpContext; + var fileResult = (new Mock(NullLogger.Instance)).Object; // Act - var state = FileResultExecutorBase.GetPreconditionState( + var state = fileResult.GetPreconditionState( httpRequestHeaders, lastModified, etag); @@ -373,9 +353,10 @@ namespace Microsoft.AspNetCore.Mvc }; httpRequestHeaders.IfModifiedSince = lastModified; actionContext.HttpContext = httpContext; + var fileResult = (new Mock(NullLogger.Instance)).Object; // Act - var state = FileResultExecutorBase.GetPreconditionState( + var state = fileResult.GetPreconditionState( httpRequestHeaders, lastModified, etag); @@ -400,9 +381,10 @@ namespace Microsoft.AspNetCore.Mvc httpRequestHeaders.IfRange = new RangeConditionHeaderValue(ifRangeString); httpRequestHeaders.IfModifiedSince = lastModified; actionContext.HttpContext = httpContext; + var fileResult = (new Mock(NullLogger.Instance)).Object; // Act - var ifRangeIsValid = FileResultExecutorBase.IfRangeValid( + var ifRangeIsValid = fileResult.IfRangeValid( httpRequestHeaders, lastModified, etag);