parent
eeac99985a
commit
2fcfc6be7c
|
|
@ -1088,6 +1088,20 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
public virtual FileContentResult File(byte[] fileContents, string contentType)
|
||||
=> File(fileContents, contentType, fileDownloadName: null);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a file with the specified <paramref name="fileContents" /> as content (<see cref="StatusCodes.Status200OK"/>),
|
||||
/// and the specified <paramref name="contentType" /> as the Content-Type.
|
||||
/// This supports range requests (<see cref="StatusCodes.Status206PartialContent"/> or
|
||||
/// <see cref="StatusCodes.Status416RangeNotSatisfiable"/> if the range is not satisfiable).
|
||||
/// </summary>
|
||||
/// <param name="fileContents">The file contents.</param>
|
||||
/// <param name="contentType">The Content-Type of the file.</param>
|
||||
/// <param name="enableRangeProcessing">Set to <c>true</c> to enable range requests processing.</param>
|
||||
/// <returns>The created <see cref="FileContentResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual FileContentResult File(byte[] fileContents, string contentType, bool enableRangeProcessing)
|
||||
=> File(fileContents, contentType, fileDownloadName: null, enableRangeProcessing: enableRangeProcessing);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a file with the specified <paramref name="fileContents" /> as content (<see cref="StatusCodes.Status200OK"/>), the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type and the specified <paramref name="fileDownloadName" /> as the suggested file name.
|
||||
|
|
@ -1102,6 +1116,25 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
public virtual FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName)
|
||||
=> new FileContentResult(fileContents, contentType) { FileDownloadName = fileDownloadName };
|
||||
|
||||
/// <summary>
|
||||
/// Returns a file with the specified <paramref name="fileContents" /> as content (<see cref="StatusCodes.Status200OK"/>), the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type and the specified <paramref name="fileDownloadName" /> as the suggested file name.
|
||||
/// This supports range requests (<see cref="StatusCodes.Status206PartialContent"/> or
|
||||
/// <see cref="StatusCodes.Status416RangeNotSatisfiable"/> if the range is not satisfiable).
|
||||
/// </summary>
|
||||
/// <param name="fileContents">The file contents.</param>
|
||||
/// <param name="contentType">The Content-Type of the file.</param>
|
||||
/// <param name="fileDownloadName">The suggested file name.</param>
|
||||
/// <param name="enableRangeProcessing">Set to <c>true</c> to enable range requests processing.</param>
|
||||
/// <returns>The created <see cref="FileContentResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName, bool enableRangeProcessing)
|
||||
=> new FileContentResult(fileContents, contentType)
|
||||
{
|
||||
FileDownloadName = fileDownloadName,
|
||||
EnableRangeProcessing = enableRangeProcessing,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns a file with the specified <paramref name="fileContents" /> as content (<see cref="StatusCodes.Status200OK"/>),
|
||||
/// and the specified <paramref name="contentType" /> as the Content-Type.
|
||||
|
|
@ -1123,6 +1156,29 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a file with the specified <paramref name="fileContents" /> as content (<see cref="StatusCodes.Status200OK"/>),
|
||||
/// and the specified <paramref name="contentType" /> as the Content-Type.
|
||||
/// This supports range requests (<see cref="StatusCodes.Status206PartialContent"/> or
|
||||
/// <see cref="StatusCodes.Status416RangeNotSatisfiable"/> if the range is not satisfiable).
|
||||
/// </summary>
|
||||
/// <param name="fileContents">The file contents.</param>
|
||||
/// <param name="contentType">The Content-Type of the file.</param>
|
||||
/// <param name="lastModified">The <see cref="DateTimeOffset"/> of when the file was last modified.</param>
|
||||
/// <param name="entityTag">The <see cref="EntityTagHeaderValue"/> associated with the file.</param>
|
||||
/// <param name="enableRangeProcessing">Set to <c>true</c> to enable range requests processing.</param>
|
||||
/// <returns>The created <see cref="FileContentResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual FileContentResult File(byte[] fileContents, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing)
|
||||
{
|
||||
return new FileContentResult(fileContents, contentType)
|
||||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = enableRangeProcessing,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a file with the specified <paramref name="fileContents" /> as content (<see cref="StatusCodes.Status200OK"/>), the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type, and the specified <paramref name="fileDownloadName" /> as the suggested file name.
|
||||
|
|
@ -1146,6 +1202,31 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a file with the specified <paramref name="fileContents" /> as content (<see cref="StatusCodes.Status200OK"/>), the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type, and the specified <paramref name="fileDownloadName" /> as the suggested file name.
|
||||
/// This supports range requests (<see cref="StatusCodes.Status206PartialContent"/> or
|
||||
/// <see cref="StatusCodes.Status416RangeNotSatisfiable"/> if the range is not satisfiable).
|
||||
/// </summary>
|
||||
/// <param name="fileContents">The file contents.</param>
|
||||
/// <param name="contentType">The Content-Type of the file.</param>
|
||||
/// <param name="fileDownloadName">The suggested file name.</param>
|
||||
/// <param name="lastModified">The <see cref="DateTimeOffset"/> of when the file was last modified.</param>
|
||||
/// <param name="entityTag">The <see cref="EntityTagHeaderValue"/> associated with the file.</param>
|
||||
/// <param name="enableRangeProcessing">Set to <c>true</c> to enable range requests processing.</param>
|
||||
/// <returns>The created <see cref="FileContentResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual FileContentResult File(byte[] fileContents, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing)
|
||||
{
|
||||
return new FileContentResult(fileContents, contentType)
|
||||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
FileDownloadName = fileDownloadName,
|
||||
EnableRangeProcessing = enableRangeProcessing,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a file in the specified <paramref name="fileStream" /> (<see cref="StatusCodes.Status200OK"/>), with the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type.
|
||||
|
|
@ -1159,6 +1240,20 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
public virtual FileStreamResult File(Stream fileStream, string contentType)
|
||||
=> File(fileStream, contentType, fileDownloadName: null);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a file in the specified <paramref name="fileStream" /> (<see cref="StatusCodes.Status200OK"/>), with the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type.
|
||||
/// This supports range requests (<see cref="StatusCodes.Status206PartialContent"/> or
|
||||
/// <see cref="StatusCodes.Status416RangeNotSatisfiable"/> if the range is not satisfiable).
|
||||
/// </summary>
|
||||
/// <param name="fileStream">The <see cref="Stream"/> with the contents of the file.</param>
|
||||
/// <param name="contentType">The Content-Type of the file.</param>
|
||||
/// <param name="enableRangeProcessing">Set to <c>true</c> to enable range requests processing.</param>
|
||||
/// <returns>The created <see cref="FileStreamResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual FileStreamResult File(Stream fileStream, string contentType, bool enableRangeProcessing)
|
||||
=> File(fileStream, contentType, fileDownloadName: null, enableRangeProcessing: enableRangeProcessing);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a file in the specified <paramref name="fileStream" /> (<see cref="StatusCodes.Status200OK"/>) with the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type and the
|
||||
|
|
@ -1174,6 +1269,26 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
public virtual FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName)
|
||||
=> new FileStreamResult(fileStream, contentType) { FileDownloadName = fileDownloadName };
|
||||
|
||||
/// <summary>
|
||||
/// Returns a file in the specified <paramref name="fileStream" /> (<see cref="StatusCodes.Status200OK"/>) with the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type and the
|
||||
/// specified <paramref name="fileDownloadName" /> as the suggested file name.
|
||||
/// This supports range requests (<see cref="StatusCodes.Status206PartialContent"/> or
|
||||
/// <see cref="StatusCodes.Status416RangeNotSatisfiable"/> if the range is not satisfiable).
|
||||
/// </summary>
|
||||
/// <param name="fileStream">The <see cref="Stream"/> with the contents of the file.</param>
|
||||
/// <param name="contentType">The Content-Type of the file.</param>
|
||||
/// <param name="fileDownloadName">The suggested file name.</param>
|
||||
/// <param name="enableRangeProcessing">Set to <c>true</c> to enable range requests processing.</param>
|
||||
/// <returns>The created <see cref="FileStreamResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName, bool enableRangeProcessing)
|
||||
=> new FileStreamResult(fileStream, contentType)
|
||||
{
|
||||
FileDownloadName = fileDownloadName,
|
||||
EnableRangeProcessing = enableRangeProcessing,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns a file in the specified <paramref name="fileStream" /> (<see cref="StatusCodes.Status200OK"/>),
|
||||
/// and the specified <paramref name="contentType" /> as the Content-Type.
|
||||
|
|
@ -1195,6 +1310,29 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a file in the specified <paramref name="fileStream" /> (<see cref="StatusCodes.Status200OK"/>),
|
||||
/// and the specified <paramref name="contentType" /> as the Content-Type.
|
||||
/// This supports range requests (<see cref="StatusCodes.Status206PartialContent"/> or
|
||||
/// <see cref="StatusCodes.Status416RangeNotSatisfiable"/> if the range is not satisfiable).
|
||||
/// </summary>
|
||||
/// <param name="fileStream">The <see cref="Stream"/> with the contents of the file.</param>
|
||||
/// <param name="contentType">The Content-Type of the file.</param>
|
||||
/// <param name="lastModified">The <see cref="DateTimeOffset"/> of when the file was last modified.</param>
|
||||
/// <param name="entityTag">The <see cref="EntityTagHeaderValue"/> associated with the file.</param>
|
||||
/// <param name="enableRangeProcessing">Set to <c>true</c> to enable range requests processing.</param>
|
||||
/// <returns>The created <see cref="FileStreamResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual FileStreamResult File(Stream fileStream, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing)
|
||||
{
|
||||
return new FileStreamResult(fileStream, contentType)
|
||||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = enableRangeProcessing,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a file in the specified <paramref name="fileStream" /> (<see cref="StatusCodes.Status200OK"/>), the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type, and the specified <paramref name="fileDownloadName" /> as the suggested file name.
|
||||
|
|
@ -1218,6 +1356,31 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a file in the specified <paramref name="fileStream" /> (<see cref="StatusCodes.Status200OK"/>), the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type, and the specified <paramref name="fileDownloadName" /> as the suggested file name.
|
||||
/// This supports range requests (<see cref="StatusCodes.Status206PartialContent"/> or
|
||||
/// <see cref="StatusCodes.Status416RangeNotSatisfiable"/> if the range is not satisfiable).
|
||||
/// </summary>
|
||||
/// <param name="fileStream">The <see cref="Stream"/> with the contents of the file.</param>
|
||||
/// <param name="contentType">The Content-Type of the file.</param>
|
||||
/// <param name="fileDownloadName">The suggested file name.</param>
|
||||
/// <param name="lastModified">The <see cref="DateTimeOffset"/> of when the file was last modified.</param>
|
||||
/// <param name="entityTag">The <see cref="EntityTagHeaderValue"/> associated with the file.</param>
|
||||
/// <param name="enableRangeProcessing">Set to <c>true</c> to enable range requests processing.</param>
|
||||
/// <returns>The created <see cref="FileStreamResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual FileStreamResult File(Stream fileStream, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing)
|
||||
{
|
||||
return new FileStreamResult(fileStream, contentType)
|
||||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
FileDownloadName = fileDownloadName,
|
||||
EnableRangeProcessing = enableRangeProcessing,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file specified by <paramref name="virtualPath" /> (<see cref="StatusCodes.Status200OK"/>) with the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type.
|
||||
|
|
@ -1231,6 +1394,20 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
public virtual VirtualFileResult File(string virtualPath, string contentType)
|
||||
=> File(virtualPath, contentType, fileDownloadName: null);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file specified by <paramref name="virtualPath" /> (<see cref="StatusCodes.Status200OK"/>) with the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type.
|
||||
/// This supports range requests (<see cref="StatusCodes.Status206PartialContent"/> or
|
||||
/// <see cref="StatusCodes.Status416RangeNotSatisfiable"/> if the range is not satisfiable).
|
||||
/// </summary>
|
||||
/// <param name="virtualPath">The virtual path of the file to be returned.</param>
|
||||
/// <param name="contentType">The Content-Type of the file.</param>
|
||||
/// <param name="enableRangeProcessing">Set to <c>true</c> to enable range requests processing.</param>
|
||||
/// <returns>The created <see cref="VirtualFileResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual VirtualFileResult File(string virtualPath, string contentType, bool enableRangeProcessing)
|
||||
=> File(virtualPath, contentType, fileDownloadName: null, enableRangeProcessing: enableRangeProcessing);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file specified by <paramref name="virtualPath" /> (<see cref="StatusCodes.Status200OK"/>) with the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type and the
|
||||
|
|
@ -1246,6 +1423,26 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
public virtual VirtualFileResult File(string virtualPath, string contentType, string fileDownloadName)
|
||||
=> new VirtualFileResult(virtualPath, contentType) { FileDownloadName = fileDownloadName };
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file specified by <paramref name="virtualPath" /> (<see cref="StatusCodes.Status200OK"/>) with the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type and the
|
||||
/// specified <paramref name="fileDownloadName" /> as the suggested file name.
|
||||
/// This supports range requests (<see cref="StatusCodes.Status206PartialContent"/> or
|
||||
/// <see cref="StatusCodes.Status416RangeNotSatisfiable"/> if the range is not satisfiable).
|
||||
/// </summary>
|
||||
/// <param name="virtualPath">The virtual path of the file to be returned.</param>
|
||||
/// <param name="contentType">The Content-Type of the file.</param>
|
||||
/// <param name="fileDownloadName">The suggested file name.</param>
|
||||
/// <param name="enableRangeProcessing">Set to <c>true</c> to enable range requests processing.</param>
|
||||
/// <returns>The created <see cref="VirtualFileResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual VirtualFileResult File(string virtualPath, string contentType, string fileDownloadName, bool enableRangeProcessing)
|
||||
=> new VirtualFileResult(virtualPath, contentType)
|
||||
{
|
||||
FileDownloadName = fileDownloadName,
|
||||
EnableRangeProcessing = enableRangeProcessing,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file specified by <paramref name="virtualPath" /> (<see cref="StatusCodes.Status200OK"/>), and the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type.
|
||||
|
|
@ -1267,6 +1464,29 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file specified by <paramref name="virtualPath" /> (<see cref="StatusCodes.Status200OK"/>), and the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type.
|
||||
/// This supports range requests (<see cref="StatusCodes.Status206PartialContent"/> or
|
||||
/// <see cref="StatusCodes.Status416RangeNotSatisfiable"/> if the range is not satisfiable).
|
||||
/// </summary>
|
||||
/// <param name="virtualPath">The virtual path of the file to be returned.</param>
|
||||
/// <param name="contentType">The Content-Type of the file.</param>
|
||||
/// <param name="lastModified">The <see cref="DateTimeOffset"/> of when the file was last modified.</param>
|
||||
/// <param name="entityTag">The <see cref="EntityTagHeaderValue"/> associated with the file.</param>
|
||||
/// <param name="enableRangeProcessing">Set to <c>true</c> to enable range requests processing.</param>
|
||||
/// <returns>The created <see cref="VirtualFileResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual VirtualFileResult File(string virtualPath, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing)
|
||||
{
|
||||
return new VirtualFileResult(virtualPath, contentType)
|
||||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = enableRangeProcessing,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file specified by <paramref name="virtualPath" /> (<see cref="StatusCodes.Status200OK"/>), the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type, and the specified <paramref name="fileDownloadName" /> as the suggested file name.
|
||||
|
|
@ -1290,6 +1510,31 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file specified by <paramref name="virtualPath" /> (<see cref="StatusCodes.Status200OK"/>), the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type, and the specified <paramref name="fileDownloadName" /> as the suggested file name.
|
||||
/// This supports range requests (<see cref="StatusCodes.Status206PartialContent"/> or
|
||||
/// <see cref="StatusCodes.Status416RangeNotSatisfiable"/> if the range is not satisfiable).
|
||||
/// </summary>
|
||||
/// <param name="virtualPath">The virtual path of the file to be returned.</param>
|
||||
/// <param name="contentType">The Content-Type of the file.</param>
|
||||
/// <param name="fileDownloadName">The suggested file name.</param>
|
||||
/// <param name="lastModified">The <see cref="DateTimeOffset"/> of when the file was last modified.</param>
|
||||
/// <param name="entityTag">The <see cref="EntityTagHeaderValue"/> associated with the file.</param>
|
||||
/// <param name="enableRangeProcessing">Set to <c>true</c> to enable range requests processing.</param>
|
||||
/// <returns>The created <see cref="VirtualFileResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual VirtualFileResult File(string virtualPath, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing)
|
||||
{
|
||||
return new VirtualFileResult(virtualPath, contentType)
|
||||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
FileDownloadName = fileDownloadName,
|
||||
EnableRangeProcessing = enableRangeProcessing,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file specified by <paramref name="physicalPath" /> (<see cref="StatusCodes.Status200OK"/>) with the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type.
|
||||
|
|
@ -1303,6 +1548,20 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
public virtual PhysicalFileResult PhysicalFile(string physicalPath, string contentType)
|
||||
=> PhysicalFile(physicalPath, contentType, fileDownloadName: null);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file specified by <paramref name="physicalPath" /> (<see cref="StatusCodes.Status200OK"/>) with the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type.
|
||||
/// This supports range requests (<see cref="StatusCodes.Status206PartialContent"/> or
|
||||
/// <see cref="StatusCodes.Status416RangeNotSatisfiable"/> if the range is not satisfiable).
|
||||
/// </summary>
|
||||
/// <param name="physicalPath">The physical path of the file to be returned.</param>
|
||||
/// <param name="contentType">The Content-Type of the file.</param>
|
||||
/// <param name="enableRangeProcessing">Set to <c>true</c> to enable range requests processing.</param>
|
||||
/// <returns>The created <see cref="PhysicalFileResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual PhysicalFileResult PhysicalFile(string physicalPath, string contentType, bool enableRangeProcessing)
|
||||
=> PhysicalFile(physicalPath, contentType, fileDownloadName: null, enableRangeProcessing: enableRangeProcessing);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file specified by <paramref name="physicalPath" /> (<see cref="StatusCodes.Status200OK"/>) with the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type and the
|
||||
|
|
@ -1321,6 +1580,30 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
string fileDownloadName)
|
||||
=> new PhysicalFileResult(physicalPath, contentType) { FileDownloadName = fileDownloadName };
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file specified by <paramref name="physicalPath" /> (<see cref="StatusCodes.Status200OK"/>) with the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type and the
|
||||
/// specified <paramref name="fileDownloadName" /> as the suggested file name.
|
||||
/// This supports range requests (<see cref="StatusCodes.Status206PartialContent"/> or
|
||||
/// <see cref="StatusCodes.Status416RangeNotSatisfiable"/> if the range is not satisfiable).
|
||||
/// </summary>
|
||||
/// <param name="physicalPath">The physical path of the file to be returned.</param>
|
||||
/// <param name="contentType">The Content-Type of the file.</param>
|
||||
/// <param name="fileDownloadName">The suggested file name.</param>
|
||||
/// <param name="enableRangeProcessing">Set to <c>true</c> to enable range requests processing.</param>
|
||||
/// <returns>The created <see cref="PhysicalFileResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual PhysicalFileResult PhysicalFile(
|
||||
string physicalPath,
|
||||
string contentType,
|
||||
string fileDownloadName,
|
||||
bool enableRangeProcessing)
|
||||
=> new PhysicalFileResult(physicalPath, contentType)
|
||||
{
|
||||
FileDownloadName = fileDownloadName,
|
||||
EnableRangeProcessing = enableRangeProcessing,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file specified by <paramref name="physicalPath" /> (<see cref="StatusCodes.Status200OK"/>), and
|
||||
/// the specified <paramref name="contentType" /> as the Content-Type.
|
||||
|
|
@ -1342,6 +1625,29 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file specified by <paramref name="physicalPath" /> (<see cref="StatusCodes.Status200OK"/>), and
|
||||
/// the specified <paramref name="contentType" /> as the Content-Type.
|
||||
/// This supports range requests (<see cref="StatusCodes.Status206PartialContent"/> or
|
||||
/// <see cref="StatusCodes.Status416RangeNotSatisfiable"/> if the range is not satisfiable).
|
||||
/// </summary>
|
||||
/// <param name="physicalPath">The physical path of the file to be returned.</param>
|
||||
/// <param name="contentType">The Content-Type of the file.</param>
|
||||
/// <param name="lastModified">The <see cref="DateTimeOffset"/> of when the file was last modified.</param>
|
||||
/// <param name="entityTag">The <see cref="EntityTagHeaderValue"/> associated with the file.</param>
|
||||
/// <param name="enableRangeProcessing">Set to <c>true</c> to enable range requests processing.</param>
|
||||
/// <returns>The created <see cref="PhysicalFileResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual PhysicalFileResult PhysicalFile(string physicalPath, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing)
|
||||
{
|
||||
return new PhysicalFileResult(physicalPath, contentType)
|
||||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = enableRangeProcessing,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file specified by <paramref name="physicalPath" /> (<see cref="StatusCodes.Status200OK"/>), the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type, and the specified <paramref name="fileDownloadName" /> as the suggested file name.
|
||||
|
|
@ -1365,6 +1671,31 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the file specified by <paramref name="physicalPath" /> (<see cref="StatusCodes.Status200OK"/>), the
|
||||
/// specified <paramref name="contentType" /> as the Content-Type, and the specified <paramref name="fileDownloadName" /> as the suggested file name.
|
||||
/// This supports range requests (<see cref="StatusCodes.Status206PartialContent"/> or
|
||||
/// <see cref="StatusCodes.Status416RangeNotSatisfiable"/> if the range is not satisfiable).
|
||||
/// </summary>
|
||||
/// <param name="physicalPath">The physical path of the file to be returned.</param>
|
||||
/// <param name="contentType">The Content-Type of the file.</param>
|
||||
/// <param name="fileDownloadName">The suggested file name.</param>
|
||||
/// <param name="lastModified">The <see cref="DateTimeOffset"/> of when the file was last modified.</param>
|
||||
/// <param name="entityTag">The <see cref="EntityTagHeaderValue"/> associated with the file.</param>
|
||||
/// <param name="enableRangeProcessing">Set to <c>true</c> to enable range requests processing.</param>
|
||||
/// <returns>The created <see cref="PhysicalFileResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual PhysicalFileResult PhysicalFile(string physicalPath, string contentType, string fileDownloadName, DateTimeOffset? lastModified, EntityTagHeaderValue entityTag, bool enableRangeProcessing)
|
||||
{
|
||||
return new PhysicalFileResult(physicalPath, contentType)
|
||||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
FileDownloadName = fileDownloadName,
|
||||
EnableRangeProcessing = enableRangeProcessing,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="UnauthorizedResult"/> that produces an <see cref="StatusCodes.Status401Unauthorized"/> response.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -52,5 +52,10 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// Gets or sets the etag associated with the <see cref="FileResult"/>.
|
||||
/// </summary>
|
||||
public EntityTagHeaderValue EntityTag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value that enables range processing for the <see cref="FileResult"/>.
|
||||
/// </summary>
|
||||
public bool EnableRangeProcessing { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -33,6 +33,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
context,
|
||||
result,
|
||||
result.FileContents.Length,
|
||||
result.EnableRangeProcessing,
|
||||
result.LastModified,
|
||||
result.EntityTag);
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
ActionContext context,
|
||||
FileResult result,
|
||||
long? fileLength,
|
||||
bool enableRangeProcessing,
|
||||
DateTimeOffset? lastModified = null,
|
||||
EntityTagHeaderValue etag = null)
|
||||
{
|
||||
|
|
@ -59,54 +60,55 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
|
||||
var request = context.HttpContext.Request;
|
||||
var httpRequestHeaders = request.GetTypedHeaders();
|
||||
var preconditionState = GetPreconditionState(httpRequestHeaders, lastModified, etag);
|
||||
|
||||
var response = context.HttpContext.Response;
|
||||
var httpResponseHeaders = response.GetTypedHeaders();
|
||||
if (lastModified.HasValue)
|
||||
{
|
||||
httpResponseHeaders.LastModified = lastModified;
|
||||
}
|
||||
if (etag != null)
|
||||
{
|
||||
httpResponseHeaders.ETag = etag;
|
||||
}
|
||||
SetLastModifiedAndEtagHeaders(response, lastModified, etag);
|
||||
|
||||
var serveBody = !HttpMethods.IsHead(request.Method);
|
||||
var preconditionState = GetPreconditionState(context, httpRequestHeaders, lastModified, etag);
|
||||
|
||||
// Short circuit if the preconditional headers process to 304 (NotModified) or 412 (PreconditionFailed)
|
||||
if (preconditionState == PreconditionState.NotModified)
|
||||
{
|
||||
serveBody = false;
|
||||
response.StatusCode = StatusCodes.Status304NotModified;
|
||||
return (range: null, rangeLength: 0, serveBody);
|
||||
}
|
||||
else if (preconditionState == PreconditionState.PreconditionFailed)
|
||||
{
|
||||
serveBody = false;
|
||||
response.StatusCode = StatusCodes.Status412PreconditionFailed;
|
||||
return (range: null, rangeLength: 0, serveBody);
|
||||
}
|
||||
|
||||
if (fileLength.HasValue)
|
||||
{
|
||||
SetAcceptRangeHeader(context);
|
||||
// Assuming the request is not a range request, the Content-Length header is set to the length of the entire file.
|
||||
// Assuming the request is not a range request, and the response body is not empty, the Content-Length header is set to
|
||||
// the length of the entire file.
|
||||
// If the request is a valid range request, this header is overwritten with the length of the range as part of the
|
||||
// range processing (see method SetContentLength).
|
||||
if (serveBody)
|
||||
{
|
||||
response.ContentLength = fileLength.Value;
|
||||
}
|
||||
if (HttpMethods.IsHead(request.Method) || HttpMethods.IsGet(request.Method))
|
||||
|
||||
// Handle range request
|
||||
if (enableRangeProcessing)
|
||||
{
|
||||
if ((preconditionState == PreconditionState.Unspecified ||
|
||||
preconditionState == PreconditionState.ShouldProcess))
|
||||
SetAcceptRangeHeader(response);
|
||||
|
||||
// If the request method is HEAD or GET, PreconditionState is Unspecified or ShouldProcess, and IfRange header is valid,
|
||||
// range should be processed and Range headers should be set
|
||||
if ((HttpMethods.IsHead(request.Method) || HttpMethods.IsGet(request.Method))
|
||||
&& (preconditionState == PreconditionState.Unspecified || preconditionState == PreconditionState.ShouldProcess)
|
||||
&& (IfRangeValid(httpRequestHeaders, lastModified, etag)))
|
||||
{
|
||||
if (IfRangeValid(context, httpRequestHeaders, lastModified, etag))
|
||||
{
|
||||
return SetRangeHeaders(context, httpRequestHeaders, fileLength.Value);
|
||||
}
|
||||
return SetRangeHeaders(context, httpRequestHeaders, fileLength.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (range: null, rangeLength: 0, serveBody: serveBody);
|
||||
return (range: null, rangeLength: 0, serveBody);
|
||||
}
|
||||
|
||||
private static void SetContentType(ActionContext context, FileResult result)
|
||||
|
|
@ -130,38 +132,25 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
}
|
||||
}
|
||||
|
||||
private static void SetAcceptRangeHeader(ActionContext context)
|
||||
private static void SetLastModifiedAndEtagHeaders(HttpResponse response, DateTimeOffset? lastModified, EntityTagHeaderValue etag)
|
||||
{
|
||||
var httpResponseHeaders = response.GetTypedHeaders();
|
||||
if (lastModified.HasValue)
|
||||
{
|
||||
httpResponseHeaders.LastModified = lastModified;
|
||||
}
|
||||
if (etag != null)
|
||||
{
|
||||
httpResponseHeaders.ETag = etag;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetAcceptRangeHeader(HttpResponse response)
|
||||
{
|
||||
var response = context.HttpContext.Response;
|
||||
response.Headers[HeaderNames.AcceptRanges] = AcceptRangeHeaderValue;
|
||||
}
|
||||
|
||||
private static PreconditionState GetEtagMatchState(
|
||||
IList<EntityTagHeaderValue> etagHeader,
|
||||
EntityTagHeaderValue etag,
|
||||
PreconditionState matchFoundState,
|
||||
PreconditionState matchNotFoundState)
|
||||
{
|
||||
if (etagHeader != null && etagHeader.Any())
|
||||
{
|
||||
var state = matchNotFoundState;
|
||||
foreach (var entityTag in etagHeader)
|
||||
{
|
||||
if (entityTag.Equals(EntityTagHeaderValue.Any) || entityTag.Compare(etag, useStrongComparison: true))
|
||||
{
|
||||
state = matchFoundState;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
return PreconditionState.Unspecified;
|
||||
}
|
||||
|
||||
internal static bool IfRangeValid(
|
||||
ActionContext context,
|
||||
RequestHeaders httpRequestHeaders,
|
||||
DateTimeOffset? lastModified = null,
|
||||
EntityTagHeaderValue etag = null)
|
||||
|
|
@ -193,7 +182,6 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
|
||||
// Internal for testing
|
||||
internal static PreconditionState GetPreconditionState(
|
||||
ActionContext context,
|
||||
RequestHeaders httpRequestHeaders,
|
||||
DateTimeOffset? lastModified = null,
|
||||
EntityTagHeaderValue etag = null)
|
||||
|
|
@ -247,6 +235,30 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
return state;
|
||||
}
|
||||
|
||||
private static PreconditionState GetEtagMatchState(
|
||||
IList<EntityTagHeaderValue> etagHeader,
|
||||
EntityTagHeaderValue etag,
|
||||
PreconditionState matchFoundState,
|
||||
PreconditionState matchNotFoundState)
|
||||
{
|
||||
if (etagHeader != null && etagHeader.Any())
|
||||
{
|
||||
var state = matchNotFoundState;
|
||||
foreach (var entityTag in etagHeader)
|
||||
{
|
||||
if (entityTag.Equals(EntityTagHeaderValue.Any) || entityTag.Compare(etag, useStrongComparison: true))
|
||||
{
|
||||
state = matchFoundState;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
return PreconditionState.Unspecified;
|
||||
}
|
||||
|
||||
private static PreconditionState GetMaxPreconditionState(params PreconditionState[] states)
|
||||
{
|
||||
var max = PreconditionState.Unspecified;
|
||||
|
|
@ -281,6 +293,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
return (range: null, rangeLength: 0, serveBody: true);
|
||||
}
|
||||
|
||||
// Requested range is not satisfiable
|
||||
if (range == null)
|
||||
{
|
||||
// 14.16 Content-Range - A server sending a response with status code 416 (Requested range not satisfiable)
|
||||
|
|
@ -292,23 +305,23 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
return (range: null, rangeLength: 0, serveBody: false);
|
||||
}
|
||||
|
||||
response.StatusCode = StatusCodes.Status206PartialContent;
|
||||
httpResponseHeaders.ContentRange = new ContentRangeHeaderValue(
|
||||
range.From.Value,
|
||||
range.To.Value,
|
||||
fileLength);
|
||||
|
||||
response.StatusCode = StatusCodes.Status206PartialContent;
|
||||
// Overwrite the Content-Length header for valid range requests with the range length.
|
||||
var rangeLength = SetContentLength(context, range);
|
||||
var rangeLength = SetContentLength(response, range);
|
||||
|
||||
return (range, rangeLength, serveBody: true);
|
||||
}
|
||||
|
||||
private static long SetContentLength(ActionContext context, RangeItemHeaderValue range)
|
||||
private static long SetContentLength(HttpResponse response, RangeItemHeaderValue range)
|
||||
{
|
||||
var start = range.From.Value;
|
||||
var end = range.To.Value;
|
||||
var length = end - start + 1;
|
||||
var response = context.HttpContext.Response;
|
||||
response.ContentLength = length;
|
||||
return length;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
context,
|
||||
result,
|
||||
fileLength,
|
||||
result.EnableRangeProcessing,
|
||||
result.LastModified,
|
||||
result.EntityTag);
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
context,
|
||||
result,
|
||||
fileInfo.Length,
|
||||
result.EnableRangeProcessing,
|
||||
lastModified,
|
||||
result.EntityTag);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ using Microsoft.Net.Http.Headers;
|
|||
|
||||
namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
||||
{
|
||||
public class VirtualFileResultExecutor : FileResultExecutorBase , IActionResultExecutor<VirtualFileResult>
|
||||
public class VirtualFileResultExecutor : FileResultExecutorBase, IActionResultExecutor<VirtualFileResult>
|
||||
{
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
|
||||
|
|
@ -54,6 +54,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
context,
|
||||
result,
|
||||
fileInfo.Length,
|
||||
result.EnableRangeProcessing,
|
||||
lastModified,
|
||||
result.EntityTag);
|
||||
|
||||
|
|
|
|||
|
|
@ -1632,14 +1632,33 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
Assert.Same(fileContents, result.FileContents);
|
||||
Assert.Equal("application/pdf", result.ContentType.ToString());
|
||||
Assert.Equal(string.Empty, result.FileDownloadName);
|
||||
Assert.False(result.EnableRangeProcessing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void File_WithContents_EnableRangeProcessing()
|
||||
{
|
||||
// Arrange
|
||||
var controller = new TestableController();
|
||||
var fileContents = new byte[0];
|
||||
|
||||
// Act
|
||||
var result = controller.File(fileContents, "application/pdf", true);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Same(fileContents, result.FileContents);
|
||||
Assert.Equal("application/pdf", result.ContentType.ToString());
|
||||
Assert.Equal(string.Empty, result.FileDownloadName);
|
||||
Assert.True(result.EnableRangeProcessing);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null)]
|
||||
[InlineData(null, "\"Etag\"")]
|
||||
[InlineData("05/01/2008 +1:00", null)]
|
||||
[InlineData("05/01/2008 +1:00", "\"Etag\"")]
|
||||
public void File_WithContents_LastModifiedAndEtag(string lastModifiedString, string entityTagString)
|
||||
[InlineData(null, null, false)]
|
||||
[InlineData(null, "\"Etag\"", false)]
|
||||
[InlineData("05/01/2008 +1:00", null, true)]
|
||||
[InlineData("05/01/2008 +1:00", "\"Etag\"", true)]
|
||||
public void File_WithContents_LastModifiedAndEtag(string lastModifiedString, string entityTagString, bool enableRangeProcessing)
|
||||
{
|
||||
// Arrange
|
||||
var controller = new TestableController();
|
||||
|
|
@ -1648,7 +1667,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
var entityTag = (entityTagString == null) ? null : new EntityTagHeaderValue(entityTagString);
|
||||
|
||||
// Act
|
||||
var result = controller.File(fileContents, "application/pdf", lastModified, entityTag);
|
||||
var result = controller.File(fileContents, "application/pdf", lastModified, entityTag, enableRangeProcessing);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
|
|
@ -1657,6 +1676,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
Assert.Equal(string.Empty, result.FileDownloadName);
|
||||
Assert.Equal(lastModified, result.LastModified);
|
||||
Assert.Equal(entityTag, result.EntityTag);
|
||||
Assert.Equal(enableRangeProcessing, result.EnableRangeProcessing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1674,14 +1694,15 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
Assert.Same(fileContents, result.FileContents);
|
||||
Assert.Equal("application/pdf", result.ContentType.ToString());
|
||||
Assert.Equal("someDownloadName", result.FileDownloadName);
|
||||
Assert.False(result.EnableRangeProcessing);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null)]
|
||||
[InlineData(null, "\"Etag\"")]
|
||||
[InlineData("05/01/2008 +1:00", null)]
|
||||
[InlineData("05/01/2008 +1:00", "\"Etag\"")]
|
||||
public void File_WithContentsAndFileDownloadName_LastModifiedAndEtag(string lastModifiedString, string entityTagString)
|
||||
[InlineData(null, null, false)]
|
||||
[InlineData(null, "\"Etag\"", false)]
|
||||
[InlineData("05/01/2008 +1:00", null, true)]
|
||||
[InlineData("05/01/2008 +1:00", "\"Etag\"", true)]
|
||||
public void File_WithContentsAndFileDownloadName_LastModifiedAndEtag(string lastModifiedString, string entityTagString, bool enableRangeProcessing)
|
||||
{
|
||||
// Arrange
|
||||
var controller = new TestableController();
|
||||
|
|
@ -1690,7 +1711,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
var entityTag = (entityTagString == null) ? null : new EntityTagHeaderValue(entityTagString);
|
||||
|
||||
// Act
|
||||
var result = controller.File(fileContents, "application/pdf", "someDownloadName", lastModified, entityTag);
|
||||
var result = controller.File(fileContents, "application/pdf", "someDownloadName", lastModified, entityTag, enableRangeProcessing);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
|
|
@ -1699,6 +1720,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
Assert.Equal("someDownloadName", result.FileDownloadName);
|
||||
Assert.Equal(lastModified, result.LastModified);
|
||||
Assert.Equal(entityTag, result.EntityTag);
|
||||
Assert.Equal(enableRangeProcessing, result.EnableRangeProcessing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1716,14 +1738,15 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
Assert.Equal(path, result.FileName);
|
||||
Assert.Equal("application/pdf", result.ContentType.ToString());
|
||||
Assert.Equal(string.Empty, result.FileDownloadName);
|
||||
Assert.False(result.EnableRangeProcessing);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null)]
|
||||
[InlineData(null, "\"Etag\"")]
|
||||
[InlineData("05/01/2008 +1:00", null)]
|
||||
[InlineData("05/01/2008 +1:00", "\"Etag\"")]
|
||||
public void File_WithPath_LastModifiedAndEtag(string lastModifiedString, string entityTagString)
|
||||
[InlineData(null, null, false)]
|
||||
[InlineData(null, "\"Etag\"", false)]
|
||||
[InlineData("05/01/2008 +1:00", null, true)]
|
||||
[InlineData("05/01/2008 +1:00", "\"Etag\"", true)]
|
||||
public void File_WithPath_LastModifiedAndEtag(string lastModifiedString, string entityTagString, bool enableRangeProcessing)
|
||||
{
|
||||
// Arrange
|
||||
var controller = new TestableController();
|
||||
|
|
@ -1732,7 +1755,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
var entityTag = (entityTagString == null) ? null : new EntityTagHeaderValue(entityTagString);
|
||||
|
||||
// Act
|
||||
var result = controller.File(path, "application/pdf", lastModified, entityTag);
|
||||
var result = controller.File(path, "application/pdf", lastModified, entityTag, enableRangeProcessing);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
|
|
@ -1741,6 +1764,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
Assert.Equal(string.Empty, result.FileDownloadName);
|
||||
Assert.Equal(lastModified, result.LastModified);
|
||||
Assert.Equal(entityTag, result.EntityTag);
|
||||
Assert.Equal(enableRangeProcessing, result.EnableRangeProcessing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1758,14 +1782,15 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
Assert.Equal(path, result.FileName);
|
||||
Assert.Equal("application/pdf", result.ContentType.ToString());
|
||||
Assert.Equal("someDownloadName", result.FileDownloadName);
|
||||
Assert.False(result.EnableRangeProcessing);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null)]
|
||||
[InlineData(null, "\"Etag\"")]
|
||||
[InlineData("05/01/2008 +1:00", null)]
|
||||
[InlineData("05/01/2008 +1:00", "\"Etag\"")]
|
||||
public void File_WithPathAndFileDownloadName_LastModifiedAndEtag(string lastModifiedString, string entityTagString)
|
||||
[InlineData(null, null, false)]
|
||||
[InlineData(null, "\"Etag\"", false)]
|
||||
[InlineData("05/01/2008 +1:00", null, true)]
|
||||
[InlineData("05/01/2008 +1:00", "\"Etag\"", true)]
|
||||
public void File_WithPathAndFileDownloadName_LastModifiedAndEtag(string lastModifiedString, string entityTagString, bool enableRangeProcessing)
|
||||
{
|
||||
// Arrange
|
||||
var controller = new TestableController();
|
||||
|
|
@ -1774,7 +1799,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
var entityTag = (entityTagString == null) ? null : new EntityTagHeaderValue(entityTagString);
|
||||
|
||||
// Act
|
||||
var result = controller.File(path, "application/pdf", "someDownloadName", lastModified, entityTag);
|
||||
var result = controller.File(path, "application/pdf", "someDownloadName", lastModified, entityTag, enableRangeProcessing);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
|
|
@ -1783,6 +1808,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
Assert.Equal("someDownloadName", result.FileDownloadName);
|
||||
Assert.Equal(lastModified, result.LastModified);
|
||||
Assert.Equal(entityTag, result.EntityTag);
|
||||
Assert.Equal(enableRangeProcessing, result.EnableRangeProcessing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1805,14 +1831,15 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
Assert.Same(fileStream, result.FileStream);
|
||||
Assert.Equal("application/pdf", result.ContentType.ToString());
|
||||
Assert.Equal(string.Empty, result.FileDownloadName);
|
||||
Assert.False(result.EnableRangeProcessing);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null)]
|
||||
[InlineData(null, "\"Etag\"")]
|
||||
[InlineData("05/01/2008 +1:00", null)]
|
||||
[InlineData("05/01/2008 +1:00", "\"Etag\"")]
|
||||
public void File_WithStream_LastModifiedAndEtag(string lastModifiedString, string entityTagString)
|
||||
[InlineData(null, null, false)]
|
||||
[InlineData(null, "\"Etag\"", false)]
|
||||
[InlineData("05/01/2008 +1:00", null, true)]
|
||||
[InlineData("05/01/2008 +1:00", "\"Etag\"", true)]
|
||||
public void File_WithStream_LastModifiedAndEtag(string lastModifiedString, string entityTagString, bool enableRangeProcessing)
|
||||
{
|
||||
// Arrange
|
||||
var mockHttpContext = new Mock<HttpContext>();
|
||||
|
|
@ -1826,7 +1853,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
var entityTag = (entityTagString == null) ? null : new EntityTagHeaderValue(entityTagString);
|
||||
|
||||
// Act
|
||||
var result = controller.File(fileStream, "application/pdf", lastModified, entityTag);
|
||||
var result = controller.File(fileStream, "application/pdf", lastModified, entityTag, enableRangeProcessing);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
|
|
@ -1835,6 +1862,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
Assert.Equal(string.Empty, result.FileDownloadName);
|
||||
Assert.Equal(lastModified, result.LastModified);
|
||||
Assert.Equal(entityTag, result.EntityTag);
|
||||
Assert.Equal(enableRangeProcessing, result.EnableRangeProcessing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1856,14 +1884,15 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
Assert.Same(fileStream, result.FileStream);
|
||||
Assert.Equal("application/pdf", result.ContentType.ToString());
|
||||
Assert.Equal("someDownloadName", result.FileDownloadName);
|
||||
Assert.False(result.EnableRangeProcessing);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, null)]
|
||||
[InlineData(null, "\"Etag\"")]
|
||||
[InlineData("05/01/2008 +1:00", null)]
|
||||
[InlineData("05/01/2008 +1:00", "\"Etag\"")]
|
||||
public void File_WithStreamAndFileDownloadName_LastModifiedAndEtag(string lastModifiedString, string entityTagString)
|
||||
[InlineData(null, null, false)]
|
||||
[InlineData(null, "\"Etag\"", false)]
|
||||
[InlineData("05/01/2008 +1:00", null, true)]
|
||||
[InlineData("05/01/2008 +1:00", "\"Etag\"", true)]
|
||||
public void File_WithStreamAndFileDownloadName_LastModifiedAndEtag(string lastModifiedString, string entityTagString, bool enableRangeProcessing)
|
||||
{
|
||||
// Arrange
|
||||
var mockHttpContext = new Mock<HttpContext>();
|
||||
|
|
@ -1876,7 +1905,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
var entityTag = (entityTagString == null) ? null : new EntityTagHeaderValue(entityTagString);
|
||||
|
||||
// Act
|
||||
var result = controller.File(fileStream, "application/pdf", "someDownloadName", lastModified, entityTag);
|
||||
var result = controller.File(fileStream, "application/pdf", "someDownloadName", lastModified, entityTag, enableRangeProcessing);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
|
|
@ -1885,6 +1914,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
Assert.Equal("someDownloadName", result.FileDownloadName);
|
||||
Assert.Equal(lastModified, result.LastModified);
|
||||
Assert.Equal(entityTag, result.EntityTag);
|
||||
Assert.Equal(enableRangeProcessing, result.EnableRangeProcessing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -2738,7 +2768,7 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
|||
var controller = new TestableController();
|
||||
|
||||
// Act
|
||||
var result = controller.RedirectToPage("page", "handler", new { test = "value"});
|
||||
var result = controller.RedirectToPage("page", "handler", new { test = "value" });
|
||||
|
||||
// Assert
|
||||
Assert.Equal("page", result.PageName);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.TestCommon;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -111,7 +110,8 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var result = new FileContentResult(byteArray, contentType)
|
||||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
|
|
@ -135,18 +135,18 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
httpResponse.Body.Seek(0, SeekOrigin.Begin);
|
||||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
var contentRange = new ContentRangeHeaderValue(start.Value, end.Value, byteArray.Length);
|
||||
Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Equal(contentLength, httpResponse.ContentLength);
|
||||
Assert.Equal(expectedString, body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteFileAsync_IfRangeHeaderValid_WritesRequestedRange()
|
||||
public async Task WriteFileAsync_IfRangeHeaderValid_WritesRangeRequest()
|
||||
{
|
||||
// Arrange
|
||||
var contentType = "text/plain";
|
||||
|
|
@ -157,7 +157,8 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var result = new FileContentResult(byteArray, contentType)
|
||||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
|
|
@ -180,18 +181,28 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
httpResponse.Body.Seek(0, SeekOrigin.Begin);
|
||||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
var contentRange = new ContentRangeHeaderValue(0, 4, byteArray.Length);
|
||||
Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Equal(5, httpResponse.ContentLength);
|
||||
Assert.Equal("Hello", body);
|
||||
|
||||
if (result.EnableRangeProcessing)
|
||||
{
|
||||
Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
var contentRange = new ContentRangeHeaderValue(0, 4, byteArray.Length);
|
||||
Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.Equal(5, httpResponse.ContentLength);
|
||||
Assert.Equal("Hello", body);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
|
||||
Assert.Equal(11, httpResponse.ContentLength);
|
||||
Assert.Equal("Hello World", body);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored()
|
||||
public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestIgnored()
|
||||
{
|
||||
// Arrange
|
||||
var contentType = "text/plain";
|
||||
|
|
@ -205,6 +216,48 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
EntityTag = entityTag
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
var requestHeaders = httpContext.Request.GetTypedHeaders();
|
||||
requestHeaders.IfMatch = new[]
|
||||
{
|
||||
new EntityTagHeaderValue("\"Etag\""),
|
||||
};
|
||||
requestHeaders.Range = new RangeHeaderValue(0, 4);
|
||||
requestHeaders.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\""));
|
||||
httpContext.Request.Method = HttpMethods.Get;
|
||||
httpContext.Response.Body = new MemoryStream();
|
||||
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||
|
||||
// Act
|
||||
await result.ExecuteResultAsync(actionContext);
|
||||
|
||||
// Assert
|
||||
var httpResponse = actionContext.HttpContext.Response;
|
||||
httpResponse.Body.Seek(0, SeekOrigin.Begin);
|
||||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Equal("Hello World", body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestIgnored()
|
||||
{
|
||||
// Arrange
|
||||
var contentType = "text/plain";
|
||||
var lastModified = DateTimeOffset.MinValue.AddDays(1);
|
||||
var entityTag = new EntityTagHeaderValue("\"Etag\"");
|
||||
var byteArray = Encoding.ASCII.GetBytes("Hello World");
|
||||
|
||||
var result = new FileContentResult(byteArray, contentType)
|
||||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
var requestHeaders = httpContext.Request.GetTypedHeaders();
|
||||
requestHeaders.IfMatch = new[]
|
||||
|
|
@ -226,7 +279,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Equal("Hello World", body);
|
||||
|
|
@ -247,7 +299,8 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var result = new FileContentResult(byteArray, contentType)
|
||||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
|
|
@ -266,7 +319,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Equal("Hello World", body);
|
||||
|
|
@ -286,7 +338,8 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var result = new FileContentResult(byteArray, contentType)
|
||||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
|
|
@ -304,16 +357,16 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
var contentRange = new ContentRangeHeaderValue(byteArray.Length);
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Equal(StatusCodes.Status416RangeNotSatisfiable, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Empty(body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteFileAsync_RangeRequested_PreconditionFailed()
|
||||
public async Task WriteFileAsync_PreconditionFailed_RangeRequestedIgnored()
|
||||
{
|
||||
// Arrange
|
||||
var contentType = "text/plain";
|
||||
|
|
@ -324,7 +377,8 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var result = new FileContentResult(byteArray, contentType)
|
||||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
|
|
@ -347,7 +401,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status412PreconditionFailed, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Null(httpResponse.ContentLength);
|
||||
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
|
||||
|
|
@ -355,7 +408,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteFileAsync_RangeRequested_NotModified()
|
||||
public async Task WriteFileAsync_NotModified_RangeRequestedIgnored()
|
||||
{
|
||||
// Arrange
|
||||
var contentType = "text/plain";
|
||||
|
|
@ -366,7 +419,8 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var result = new FileContentResult(byteArray, contentType)
|
||||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
|
|
@ -389,7 +443,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status304NotModified, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Null(httpResponse.ContentLength);
|
||||
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
|
||||
|
|
|
|||
|
|
@ -297,7 +297,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
|
||||
// Act
|
||||
var state = FileResultExecutorBase.GetPreconditionState(
|
||||
actionContext,
|
||||
httpRequestHeaders,
|
||||
lastModified,
|
||||
etag);
|
||||
|
|
@ -334,7 +333,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
|
||||
// Act
|
||||
var state = FileResultExecutorBase.GetPreconditionState(
|
||||
actionContext,
|
||||
httpRequestHeaders,
|
||||
lastModified,
|
||||
etag);
|
||||
|
|
@ -370,7 +368,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
|
||||
// Act
|
||||
var state = FileResultExecutorBase.GetPreconditionState(
|
||||
actionContext,
|
||||
httpRequestHeaders,
|
||||
lastModified,
|
||||
etag);
|
||||
|
|
@ -398,7 +395,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
|
||||
// Act
|
||||
var ifRangeIsValid = FileResultExecutorBase.IfRangeValid(
|
||||
actionContext,
|
||||
httpRequestHeaders,
|
||||
lastModified,
|
||||
etag);
|
||||
|
|
@ -460,7 +456,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
|
||||
public Task ExecuteAsync(ActionContext context, EmptyFileResult result)
|
||||
{
|
||||
SetHeadersAndLog(context, result, 0L);
|
||||
SetHeadersAndLog(context, result, 0L, true);
|
||||
result.WasWriteFileCalled = true;
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.TestCommon;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -95,6 +94,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
|
|
@ -119,11 +119,11 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
var contentRange = new ContentRangeHeaderValue(start.Value, end.Value, byteArray.Length);
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Equal(contentLength, httpResponse.ContentLength);
|
||||
Assert.Equal(expectedString, body);
|
||||
}
|
||||
|
|
@ -143,6 +143,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
|
|
@ -165,16 +166,59 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
httpResponse.Body.Seek(0, SeekOrigin.Begin);
|
||||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
var contentRange = new ContentRangeHeaderValue(0, 4, byteArray.Length);
|
||||
Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
var contentRange = new ContentRangeHeaderValue(0, 4, byteArray.Length);
|
||||
Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.Equal(5, httpResponse.ContentLength);
|
||||
Assert.Equal("Hello", body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored()
|
||||
{
|
||||
// Arrange
|
||||
var contentType = "text/plain";
|
||||
var lastModified = DateTimeOffset.MinValue;
|
||||
var entityTag = new EntityTagHeaderValue("\"Etag\"");
|
||||
var byteArray = Encoding.ASCII.GetBytes("Hello World");
|
||||
var readStream = new MemoryStream(byteArray);
|
||||
readStream.SetLength(11);
|
||||
|
||||
var result = new FileStreamResult(readStream, contentType)
|
||||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
var requestHeaders = httpContext.Request.GetTypedHeaders();
|
||||
requestHeaders.IfMatch = new[]
|
||||
{
|
||||
new EntityTagHeaderValue("\"Etag\""),
|
||||
};
|
||||
requestHeaders.Range = new RangeHeaderValue(0, 4);
|
||||
requestHeaders.IfRange = new RangeConditionHeaderValue(DateTimeOffset.MinValue);
|
||||
httpContext.Request.Method = HttpMethods.Get;
|
||||
httpContext.Response.Body = new MemoryStream();
|
||||
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||
|
||||
// Act
|
||||
await result.ExecuteResultAsync(actionContext);
|
||||
|
||||
// Assert
|
||||
var httpResponse = actionContext.HttpContext.Response;
|
||||
httpResponse.Body.Seek(0, SeekOrigin.Begin);
|
||||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Equal("Hello World", body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored()
|
||||
{
|
||||
|
|
@ -190,6 +234,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
|
|
@ -235,6 +280,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
|
|
@ -254,7 +300,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Equal("Hello World", body);
|
||||
|
|
@ -276,6 +321,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
|
|
@ -293,11 +339,12 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
var contentRange = new ContentRangeHeaderValue(byteArray.Length);
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Equal(StatusCodes.Status416RangeNotSatisfiable, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Equal(11, httpResponse.ContentLength);
|
||||
Assert.Empty(body);
|
||||
}
|
||||
|
||||
|
|
@ -315,6 +362,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
|
|
@ -337,7 +385,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status412PreconditionFailed, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Null(httpResponse.ContentLength);
|
||||
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
|
||||
|
|
@ -345,7 +392,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteFileAsync_RangeRequested_NotModified()
|
||||
public async Task WriteFileAsync_NotModified_RangeRequestedIgnored()
|
||||
{
|
||||
// Arrange
|
||||
var contentType = "text/plain";
|
||||
|
|
@ -358,6 +405,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
|
|
@ -380,7 +428,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status304NotModified, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Null(httpResponse.ContentLength);
|
||||
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
|
||||
|
|
@ -404,6 +451,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
{
|
||||
LastModified = lastModified,
|
||||
EntityTag = entityTag,
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
|
|
@ -425,13 +473,12 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
httpResponse.Body.Seek(0, SeekOrigin.Begin);
|
||||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
var contentRange = new ContentRangeHeaderValue(byteArray.Length);
|
||||
Assert.Equal(StatusCodes.Status416RangeNotSatisfiable, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Equal(contentRange.ToString(), httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.Equal(lastModified.ToString("R"), httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Empty(body);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ using Microsoft.AspNetCore.Http;
|
|||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.TestCommon;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -63,6 +62,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
// Arrange
|
||||
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
|
||||
var result = new TestPhysicalFileResult(path, "text/plain");
|
||||
result.EnableRangeProcessing = true;
|
||||
var httpContext = GetHttpContext();
|
||||
var requestHeaders = httpContext.Request.GetTypedHeaders();
|
||||
requestHeaders.IfModifiedSince = DateTimeOffset.MinValue;
|
||||
|
|
@ -97,6 +97,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
|
||||
var result = new TestPhysicalFileResult(path, "text/plain");
|
||||
var entityTag = result.EntityTag = new EntityTagHeaderValue("\"Etag\"");
|
||||
result.EnableRangeProcessing = true;
|
||||
var httpContext = GetHttpContext();
|
||||
var requestHeaders = httpContext.Request.GetTypedHeaders();
|
||||
requestHeaders.IfModifiedSince = DateTimeOffset.MinValue;
|
||||
|
|
@ -124,12 +125,42 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
Assert.Equal("File", body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored()
|
||||
{
|
||||
// Arrange
|
||||
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
|
||||
var result = new TestPhysicalFileResult(path, "text/plain");
|
||||
var entityTag = result.EntityTag = new EntityTagHeaderValue("\"Etag\"");
|
||||
var httpContext = GetHttpContext();
|
||||
var requestHeaders = httpContext.Request.GetTypedHeaders();
|
||||
requestHeaders.IfModifiedSince = DateTimeOffset.MinValue;
|
||||
requestHeaders.Range = new RangeHeaderValue(0, 3);
|
||||
requestHeaders.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\""));
|
||||
httpContext.Request.Method = HttpMethods.Get;
|
||||
httpContext.Response.Body = new MemoryStream();
|
||||
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||
|
||||
// Act
|
||||
await result.ExecuteResultAsync(actionContext);
|
||||
|
||||
// Assert
|
||||
var httpResponse = actionContext.HttpContext.Response;
|
||||
httpResponse.Body.Seek(0, SeekOrigin.Begin);
|
||||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
|
||||
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal("FilePathResultTestFile contents<74>", body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored()
|
||||
{
|
||||
// Arrange
|
||||
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
|
||||
var result = new TestPhysicalFileResult(path, "text/plain");
|
||||
result.EnableRangeProcessing = true;
|
||||
var entityTag = result.EntityTag = new EntityTagHeaderValue("\"Etag\"");
|
||||
var httpContext = GetHttpContext();
|
||||
var requestHeaders = httpContext.Request.GetTypedHeaders();
|
||||
|
|
@ -149,7 +180,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal("FilePathResultTestFile contents<74>", body);
|
||||
}
|
||||
|
|
@ -158,7 +188,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
[InlineData("0-5")]
|
||||
[InlineData("bytes = ")]
|
||||
[InlineData("bytes = 1-4, 5-11")]
|
||||
public async Task WriteFileAsync_RangeRequestIgnored(string rangeString)
|
||||
public async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(string rangeString)
|
||||
{
|
||||
// Arrange
|
||||
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
|
||||
|
|
@ -180,7 +210,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal("FilePathResultTestFile contents<74>", body);
|
||||
|
|
@ -194,6 +223,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
// Arrange
|
||||
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
|
||||
var result = new TestPhysicalFileResult(path, "text/plain");
|
||||
result.EnableRangeProcessing = true;
|
||||
var httpContext = GetHttpContext();
|
||||
var requestHeaders = httpContext.Request.GetTypedHeaders();
|
||||
requestHeaders.IfModifiedSince = DateTimeOffset.MinValue;
|
||||
|
|
@ -224,6 +254,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
// Arrange
|
||||
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
|
||||
var result = new TestPhysicalFileResult(path, "text/plain");
|
||||
result.EnableRangeProcessing = true;
|
||||
var httpContext = GetHttpContext();
|
||||
var requestHeaders = httpContext.Request.GetTypedHeaders();
|
||||
requestHeaders.IfUnmodifiedSince = DateTimeOffset.MinValue;
|
||||
|
|
@ -241,7 +272,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status412PreconditionFailed, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Null(httpResponse.ContentLength);
|
||||
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
|
||||
|
|
@ -254,6 +284,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
// Arrange
|
||||
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
|
||||
var result = new TestPhysicalFileResult(path, "text/plain");
|
||||
result.EnableRangeProcessing = true;
|
||||
var httpContext = GetHttpContext();
|
||||
var requestHeaders = httpContext.Request.GetTypedHeaders();
|
||||
requestHeaders.IfModifiedSince = DateTimeOffset.MinValue.AddDays(1);
|
||||
|
|
@ -271,7 +302,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status304NotModified, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Null(httpResponse.ContentLength);
|
||||
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
|
||||
|
|
@ -321,16 +351,16 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 3, "File", 4)]
|
||||
[InlineData(8, 13, "Result", 6)]
|
||||
[InlineData(null, 3, "ts¡", 3)]
|
||||
[InlineData(8, null, "ResultTestFile contents¡", 26)]
|
||||
public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(long? start, long? end, string expectedString, long contentLength)
|
||||
[InlineData(0, 3, 4)]
|
||||
[InlineData(8, 13, 6)]
|
||||
[InlineData(null, 3, 3)]
|
||||
[InlineData(8, null, 26)]
|
||||
public async Task ExecuteResultAsync_CallsSendFileAsyncWithRequestedRange_IfIHttpSendFilePresent(long? start, long? end, long contentLength)
|
||||
{
|
||||
// Arrange
|
||||
var path = Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt"));
|
||||
var result = new TestPhysicalFileResult(path, "text/plain");
|
||||
|
||||
result.EnableRangeProcessing = true;
|
||||
var sendFile = new TestSendFileFeature();
|
||||
var httpContext = GetHttpContext();
|
||||
httpContext.Features.Set<IHttpSendFileFeature>(sendFile);
|
||||
|
|
@ -351,7 +381,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
Assert.Equal(Path.GetFullPath(Path.Combine("TestFiles", "FilePathResultTestFile.txt")), sendFile.Name);
|
||||
Assert.Equal(start, sendFile.Offset);
|
||||
Assert.Equal(contentLength, sendFile.Length);
|
||||
Assert.Equal(CancellationToken.None, sendFile.Token);
|
||||
Assert.Equal(CancellationToken.None, sendFile.Token);
|
||||
var contentRange = new ContentRangeHeaderValue(start.Value, end.Value, 34);
|
||||
Assert.Equal(StatusCodes.Status206PartialContent, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ using Microsoft.AspNetCore.Http;
|
|||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.TestCommon;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -66,6 +65,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var path = Path.GetFullPath("helllo.txt");
|
||||
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
|
||||
var result = new TestVirtualFileResult(path, contentType);
|
||||
result.EnableRangeProcessing = true;
|
||||
var appEnvironment = new Mock<IHostingEnvironment>();
|
||||
appEnvironment.Setup(app => app.WebRootFileProvider)
|
||||
.Returns(GetFileProvider(path));
|
||||
|
|
@ -110,6 +110,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var path = Path.GetFullPath("helllo.txt");
|
||||
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
|
||||
var result = new TestVirtualFileResult(path, contentType);
|
||||
result.EnableRangeProcessing = true;
|
||||
var appEnvironment = new Mock<IHostingEnvironment>();
|
||||
appEnvironment.Setup(app => app.WebRootFileProvider)
|
||||
.Returns(GetFileProvider(path));
|
||||
|
|
@ -148,6 +149,47 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
Assert.Equal("File", body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteFileAsync_RangeProcessingNotEnabled_RangeRequestedIgnored()
|
||||
{
|
||||
// Arrange
|
||||
var path = Path.GetFullPath("helllo.txt");
|
||||
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
|
||||
var result = new TestVirtualFileResult(path, contentType);
|
||||
var appEnvironment = new Mock<IHostingEnvironment>();
|
||||
appEnvironment.Setup(app => app.WebRootFileProvider)
|
||||
.Returns(GetFileProvider(path));
|
||||
|
||||
var httpContext = GetHttpContext();
|
||||
httpContext.Response.Body = new MemoryStream();
|
||||
httpContext.RequestServices = new ServiceCollection()
|
||||
.AddSingleton(appEnvironment.Object)
|
||||
.AddTransient<IActionResultExecutor<VirtualFileResult>, TestVirtualFileResultExecutor>()
|
||||
.AddTransient<ILoggerFactory, LoggerFactory>()
|
||||
.BuildServiceProvider();
|
||||
|
||||
var entityTag = result.EntityTag = new EntityTagHeaderValue("\"Etag\"");
|
||||
var requestHeaders = httpContext.Request.GetTypedHeaders();
|
||||
requestHeaders.IfModifiedSince = DateTimeOffset.MinValue;
|
||||
requestHeaders.Range = new RangeHeaderValue(0, 3);
|
||||
requestHeaders.IfRange = new RangeConditionHeaderValue(new EntityTagHeaderValue("\"Etag\""));
|
||||
httpContext.Request.Method = HttpMethods.Get;
|
||||
httpContext.Response.Body = new MemoryStream();
|
||||
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||
|
||||
// Act
|
||||
await result.ExecuteResultAsync(actionContext);
|
||||
|
||||
// Assert
|
||||
var httpResponse = actionContext.HttpContext.Response;
|
||||
httpResponse.Body.Seek(0, SeekOrigin.Begin);
|
||||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Equal("FilePathResultTestFile contents¡", body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteFileAsync_IfRangeHeaderInvalid_RangeRequestedIgnored()
|
||||
{
|
||||
|
|
@ -155,6 +197,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var path = Path.GetFullPath("helllo.txt");
|
||||
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
|
||||
var result = new TestVirtualFileResult(path, contentType);
|
||||
result.EnableRangeProcessing = true;
|
||||
var appEnvironment = new Mock<IHostingEnvironment>();
|
||||
appEnvironment.Setup(app => app.WebRootFileProvider)
|
||||
.Returns(GetFileProvider(path));
|
||||
|
|
@ -186,7 +229,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
|
||||
Assert.Equal(entityTag.ToString(), httpResponse.Headers[HeaderNames.ETag]);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Equal("FilePathResultTestFile contents¡", body);
|
||||
}
|
||||
|
||||
|
|
@ -194,12 +236,13 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
[InlineData("0-5")]
|
||||
[InlineData("bytes = ")]
|
||||
[InlineData("bytes = 1-4, 5-11")]
|
||||
public async Task WriteFileAsync_RangeRequestIgnored(string rangeString)
|
||||
public async Task WriteFileAsync_RangeHeaderMalformed_RangeRequestIgnored(string rangeString)
|
||||
{
|
||||
// Arrange
|
||||
var path = Path.GetFullPath("helllo.txt");
|
||||
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
|
||||
var result = new TestVirtualFileResult(path, contentType);
|
||||
result.EnableRangeProcessing = true;
|
||||
var appEnvironment = new Mock<IHostingEnvironment>();
|
||||
appEnvironment.Setup(app => app.WebRootFileProvider)
|
||||
.Returns(GetFileProvider(path));
|
||||
|
|
@ -228,7 +271,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status200OK, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
|
||||
Assert.Equal("FilePathResultTestFile contents¡", body);
|
||||
|
|
@ -243,6 +285,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var path = Path.GetFullPath("helllo.txt");
|
||||
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
|
||||
var result = new TestVirtualFileResult(path, contentType);
|
||||
result.EnableRangeProcessing = true;
|
||||
var appEnvironment = new Mock<IHostingEnvironment>();
|
||||
appEnvironment.Setup(app => app.WebRootFileProvider)
|
||||
.Returns(GetFileProvider(path));
|
||||
|
|
@ -285,6 +328,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var path = Path.GetFullPath("helllo.txt");
|
||||
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
|
||||
var result = new TestVirtualFileResult(path, contentType);
|
||||
result.EnableRangeProcessing = true;
|
||||
var appEnvironment = new Mock<IHostingEnvironment>();
|
||||
appEnvironment.Setup(app => app.WebRootFileProvider)
|
||||
.Returns(GetFileProvider(path));
|
||||
|
|
@ -313,7 +357,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status412PreconditionFailed, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Null(httpResponse.ContentLength);
|
||||
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
|
||||
|
|
@ -327,6 +370,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var path = Path.GetFullPath("helllo.txt");
|
||||
var contentType = "text/plain; charset=us-ascii; p1=p1-value";
|
||||
var result = new TestVirtualFileResult(path, contentType);
|
||||
result.EnableRangeProcessing = true;
|
||||
var appEnvironment = new Mock<IHostingEnvironment>();
|
||||
appEnvironment.Setup(app => app.WebRootFileProvider)
|
||||
.Returns(GetFileProvider(path));
|
||||
|
|
@ -355,7 +399,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var streamReader = new StreamReader(httpResponse.Body);
|
||||
var body = streamReader.ReadToEndAsync().Result;
|
||||
Assert.Equal(StatusCodes.Status304NotModified, httpResponse.StatusCode);
|
||||
Assert.Equal("bytes", httpResponse.Headers[HeaderNames.AcceptRanges]);
|
||||
Assert.Null(httpResponse.ContentLength);
|
||||
Assert.Empty(httpResponse.Headers[HeaderNames.ContentRange]);
|
||||
Assert.NotEmpty(httpResponse.Headers[HeaderNames.LastModified]);
|
||||
|
|
@ -454,6 +497,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
var result = new TestVirtualFileResult(path, "text/plain")
|
||||
{
|
||||
FileProvider = GetFileProvider(path),
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
var sendFile = new TestSendFileFeature();
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -189,6 +189,24 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
Assert.Equal("attachment; filename=downloadName.txt; filename*=UTF-8''downloadName.txt", contentDisposition);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FileFromDisk_ReturnsFileWithFileName_RangeProcessingNotEnabled_RangeRequestedIgnored()
|
||||
{
|
||||
// Arrange
|
||||
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/DownloadFiles/DownloadFromDiskWithFileName");
|
||||
httpRequestMessage.Headers.Range = new RangeHeaderValue(0, 6);
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(httpRequestMessage);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("This is a sample text file", body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FileFromDisk_ReturnsFileWithFileName_IfRangeHeaderValid_RangeRequest_WithLastModifiedAndEtag()
|
||||
{
|
||||
|
|
@ -259,11 +277,11 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
var response = await Client.SendAsync(httpRequestMessage);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode);
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.NotNull(body);
|
||||
Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode);
|
||||
Assert.Equal(expectedBody, body);
|
||||
}
|
||||
|
||||
|
|
@ -299,12 +317,12 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
|
||||
// Act
|
||||
var response = await Client.SendAsync(httpRequestMessage);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.RequestedRangeNotSatisfiable, response.StatusCode);
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Empty(body);
|
||||
}
|
||||
|
||||
|
|
@ -329,6 +347,24 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
Assert.Equal("attachment; filename=downloadName.txt; filename*=UTF-8''downloadName.txt", contentDisposition);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FileFromStream_ReturnsFileWithFileName_RangeProcessingNotEnabled_RangeRequestedIgnored()
|
||||
{
|
||||
// Arrange
|
||||
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/DownloadFiles/DownloadFromStreamWithFileName");
|
||||
httpRequestMessage.Headers.Range = new RangeHeaderValue(0, 6);
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(httpRequestMessage);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("This is sample text from a stream", body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FileFromStream_ReturnsFileWithFileName_IfRangeHeaderValid_RangeRequest()
|
||||
{
|
||||
|
|
@ -339,13 +375,13 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
|
||||
// Act
|
||||
var response = await Client.SendAsync(httpRequestMessage);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode);
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.NotNull(body);
|
||||
Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode);
|
||||
Assert.Equal("This is", body);
|
||||
}
|
||||
|
||||
|
|
@ -361,10 +397,8 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
var response = await Client.SendAsync(httpRequestMessage);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("This is sample text from a stream", body);
|
||||
}
|
||||
|
||||
|
|
@ -397,13 +431,13 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
|
||||
// Act
|
||||
var response = await Client.SendAsync(httpRequestMessage);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode);
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.NotNull(body);
|
||||
Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode);
|
||||
Assert.Equal(expectedBody, body);
|
||||
}
|
||||
|
||||
|
|
@ -439,12 +473,15 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
|
||||
// Act
|
||||
var response = await Client.SendAsync(httpRequestMessage);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
Assert.NotNull(body);
|
||||
Assert.Equal(HttpStatusCode.RequestedRangeNotSatisfiable, response.StatusCode);
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Empty(body);
|
||||
}
|
||||
|
||||
|
|
@ -470,7 +507,25 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FileFromBinaryData_ReturnsFileWithFileName_IfRangeHeaderValid_RangeRequest()
|
||||
public async Task FileFromBinaryData_ReturnsFileWithFileName_RangeProcessingNotEnabled_RangeRequestedIgnored()
|
||||
{
|
||||
// Arrange
|
||||
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/DownloadFiles/DownloadFromBinaryDataWithFileName");
|
||||
httpRequestMessage.Headers.Range = new RangeHeaderValue(0, 6);
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(httpRequestMessage);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("This is a sample text from a binary array", body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FileFromBinaryData_ReturnsFileWithFileName_IfRangeHeaderValid()
|
||||
{
|
||||
// Arrange
|
||||
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/DownloadFiles/DownloadFromBinaryDataWithFileName_WithEtag");
|
||||
|
|
@ -479,13 +534,13 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
|
||||
// Act
|
||||
var response = await Client.SendAsync(httpRequestMessage);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode);
|
||||
// Assert
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.NotNull(body);
|
||||
Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode);
|
||||
Assert.Equal("This is", body);
|
||||
}
|
||||
|
||||
|
|
@ -557,6 +612,24 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
Assert.Equal("attachment; filename=downloadName.txt; filename*=UTF-8''downloadName.txt", contentDisposition);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FileFromEmbeddedResources_ReturnsFileWithFileName_RangeProcessingNotEnabled_RangeRequestedIgnored()
|
||||
{
|
||||
// Arrange
|
||||
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost/EmbeddedFiles/DownloadFileWithFileName_RangeProcessingNotEnabled");
|
||||
httpRequestMessage.Headers.Range = new RangeHeaderValue(0, 6);
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(httpRequestMessage);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.ToString());
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("Sample text file as embedded resource.", body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FileFromEmbeddedResources_ReturnsFileWithFileName_IfRangeHeaderValid_RangeRequest()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace FilesWebSite
|
|||
public IActionResult DownloadFromDisk()
|
||||
{
|
||||
var path = Path.Combine(_hostingEnvironment.ContentRootPath, "sample.txt");
|
||||
return PhysicalFile(path, "text/plain");
|
||||
return PhysicalFile(path, "text/plain", true);
|
||||
}
|
||||
|
||||
public IActionResult DownloadFromDisk_WithLastModifiedAndEtag()
|
||||
|
|
@ -30,7 +30,7 @@ namespace FilesWebSite
|
|||
var path = Path.Combine(_hostingEnvironment.ContentRootPath, "sample.txt");
|
||||
var lastModified = new DateTimeOffset(year: 1999, month: 11, day: 04, hour: 3, minute: 0, second: 0, offset: new TimeSpan(0));
|
||||
var entityTag = new EntityTagHeaderValue("\"Etag\"");
|
||||
return PhysicalFile(path, "text/plain", lastModified, entityTag);
|
||||
return PhysicalFile(path, "text/plain", lastModified, entityTag, true);
|
||||
}
|
||||
|
||||
public IActionResult DownloadFromDiskWithFileName()
|
||||
|
|
@ -44,7 +44,7 @@ namespace FilesWebSite
|
|||
var path = Path.Combine(_hostingEnvironment.ContentRootPath, "sample.txt");
|
||||
var lastModified = new DateTimeOffset(year: 1999, month: 11, day: 04, hour: 3, minute: 0, second: 0, offset: new TimeSpan(0));
|
||||
var entityTag = new EntityTagHeaderValue("\"Etag\"");
|
||||
return PhysicalFile(path, "text/plain", "downloadName.txt", lastModified, entityTag);
|
||||
return PhysicalFile(path, "text/plain", "downloadName.txt", lastModified, entityTag, true);
|
||||
}
|
||||
|
||||
public IActionResult DownloadFromStream()
|
||||
|
|
@ -55,7 +55,7 @@ namespace FilesWebSite
|
|||
writer.Flush();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
return File(stream, "text/plain");
|
||||
return File(stream, "text/plain", true);
|
||||
}
|
||||
|
||||
public IActionResult DownloadFromStreamWithFileName()
|
||||
|
|
@ -77,13 +77,13 @@ namespace FilesWebSite
|
|||
writer.Flush();
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
var entityTag = new EntityTagHeaderValue("\"Etag\"");
|
||||
return File(stream, "text/plain", "downloadName.txt", lastModified: null, entityTag: entityTag);
|
||||
return File(stream, "text/plain", "downloadName.txt", lastModified: null, entityTag: entityTag, enableRangeProcessing: true);
|
||||
}
|
||||
|
||||
public IActionResult DownloadFromBinaryData()
|
||||
{
|
||||
var data = Encoding.UTF8.GetBytes("This is a sample text from a binary array");
|
||||
return File(data, "text/plain");
|
||||
return File(data, "text/plain", true);
|
||||
}
|
||||
|
||||
public IActionResult DownloadFromBinaryDataWithFileName()
|
||||
|
|
@ -96,7 +96,7 @@ namespace FilesWebSite
|
|||
{
|
||||
var data = Encoding.UTF8.GetBytes("This is a sample text from a binary array");
|
||||
var entityTag = new EntityTagHeaderValue("\"Etag\"");
|
||||
return File(data, "text/plain", "downloadName.txt", lastModified: null, entityTag: entityTag);
|
||||
return File(data, "text/plain", "downloadName.txt", lastModified: null, entityTag: entityTag, enableRangeProcessing: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,17 @@ namespace FilesWebSite
|
|||
return new VirtualFileResult("/Greetings.txt", "text/plain")
|
||||
{
|
||||
FileProvider = new EmbeddedFileProvider(GetType().GetTypeInfo().Assembly, "FilesWebSite.EmbeddedResources"),
|
||||
FileDownloadName = "downloadName.txt"
|
||||
FileDownloadName = "downloadName.txt",
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
}
|
||||
|
||||
public IActionResult DownloadFileWithFileName_RangeProcessingNotEnabled()
|
||||
{
|
||||
return new VirtualFileResult("/Greetings.txt", "text/plain")
|
||||
{
|
||||
FileProvider = new EmbeddedFileProvider(GetType().GetTypeInfo().Assembly, "FilesWebSite.EmbeddedResources"),
|
||||
FileDownloadName = "downloadName.txt",
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -23,7 +33,8 @@ namespace FilesWebSite
|
|||
var file = new VirtualFileResult("/Greetings.txt", "text/plain")
|
||||
{
|
||||
FileProvider = new EmbeddedFileProvider(GetType().GetTypeInfo().Assembly, "FilesWebSite.EmbeddedResources"),
|
||||
FileDownloadName = "downloadName.txt"
|
||||
FileDownloadName = "downloadName.txt",
|
||||
EnableRangeProcessing = true,
|
||||
};
|
||||
|
||||
file.EntityTag = new Microsoft.Net.Http.Headers.EntityTagHeaderValue("\"Etag\"");
|
||||
|
|
|
|||
Loading…
Reference in New Issue