a1ea34bc01
Consolidate data and config into separate folders that will be expected to be mapped in the container Reviewed-on: #1 Co-authored-by: Huy Nguyen <ecenshu@gmail.com> Co-committed-by: Huy Nguyen <ecenshu@gmail.com>
53 lines
1.7 KiB
C#
53 lines
1.7 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
||
|
||
namespace TinfoilVibeServer.Controllers;
|
||
|
||
public class CancelableFileResult : FileResult
|
||
{
|
||
private readonly Stream _fileStream;
|
||
|
||
public CancelableFileResult(string contentType, Stream fileStream)
|
||
: base(contentType)
|
||
{
|
||
_fileStream = fileStream ?? throw new ArgumentNullException(nameof(fileStream));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Allows you to set a suggested download name.
|
||
/// It will be sent in a “Content‑Disposition” header.
|
||
/// </summary>
|
||
public new string? FileDownloadName { get; set; }
|
||
|
||
public override async Task ExecuteResultAsync(ActionContext context)
|
||
{
|
||
var response = context.HttpContext.Response;
|
||
|
||
if (!string.IsNullOrEmpty(FileDownloadName))
|
||
{
|
||
// Typical “attachment” disposition – most browsers honour it.
|
||
response.Headers.Append("Content-Disposition",
|
||
$"attachment; filename=\"{FileDownloadName}\"");
|
||
}
|
||
|
||
// The request‑aborted token tells the stream copy to stop ASAP
|
||
var cancellationToken = context.HttpContext.RequestAborted;
|
||
|
||
try
|
||
{
|
||
// Copy the file to the response body in 8 KiB chunks
|
||
await _fileStream.CopyToAsync(
|
||
response.Body,
|
||
bufferSize: 81920, // 80 KiB – default for Stream.CopyToAsync
|
||
cancellationToken);
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
// The client disconnected – nothing to do.
|
||
// Swallowing keeps the API from returning a 500 error.
|
||
}
|
||
finally
|
||
{
|
||
await _fileStream.DisposeAsync();
|
||
}
|
||
}
|
||
} |