|
| 1 | +# Handling Files |
| 2 | + |
| 3 | +## File Uploads |
| 4 | +`IFormFile` or `IFormFileCollection` in ASP.NET Core are used to handle file uploads with form parameter binding. The IFormFile interface represents a file sent with the HttpRequest, and IFormFileCollection is a collection of IFormFile objects. |
| 5 | + |
| 6 | +``` csharp |
| 7 | +public record UploadBookRequest(string Title, [FromForm] string Author, IFormFile BookFile); |
| 8 | + |
| 9 | +public record UploadBookResponse(string FileName, long FileSize); |
| 10 | + |
| 11 | +internal class UploadBookRequestValidator : AbstractValidator<UploadBookRequest> |
| 12 | +{ |
| 13 | + public UploadBookRequestValidator() |
| 14 | + { |
| 15 | + RuleFor(x => x.Title).NotEmpty(); |
| 16 | + RuleFor(x => x.Author).NotEmpty(); |
| 17 | + RuleFor(x => x.BookFile).NotEmpty(); |
| 18 | + } |
| 19 | +} |
| 20 | + |
| 21 | +[MapToGroup<BooksV2RouteGroup>()] |
| 22 | +internal class UploadBook |
| 23 | + : WebResultEndpoint<UploadBookRequest, UploadBookResponse> |
| 24 | +{ |
| 25 | + protected override void Configure( |
| 26 | + IServiceProvider serviceProvider, |
| 27 | + IRouteGroupConfigurator? parentRouteGroup) |
| 28 | + { |
| 29 | + MapPost("/upload/{Title}") |
| 30 | + .DisableAntiforgery() |
| 31 | + .Produces<UploadBookResponse>(); |
| 32 | + } |
| 33 | + |
| 34 | + protected override Task<Result<UploadBookResponse>> HandleAsync( |
| 35 | + UploadBookRequest req, |
| 36 | + CancellationToken ct) |
| 37 | + { |
| 38 | + // Process file upload |
| 39 | + // ... |
| 40 | + // |
| 41 | +
|
| 42 | + return Task.FromResult(Result.Ok(new UploadBookResponse( |
| 43 | + req.BookFile.FileName, |
| 44 | + req.BookFile.Length))); |
| 45 | + } |
| 46 | +} |
| 47 | +``` |
| 48 | +In this example, the `UploadBookRequest` record includes a file upload parameter `IFormFile BookFile`. The `UploadBook` endpoint handles the file upload and returns a response with the file name and size. |
| 49 | + |
| 50 | +>**Note**: The `DisableAntiforgery` method is used to disable CSRF protection for this endpoint. This is necessary for file uploads, as the default behavior of ASP.NET Core is to require an antiforgery token for all POST requests. However, you should be cautious when disabling CSRF protection and ensure that your application is secure against CSRF attacks. |
| 51 | +
|
| 52 | +## File Downloads |
| 53 | +Returning `Results.File()` or `Results.Stream()` from a `MinimalEndpoint` can be used to return files from an endpoint. The file can be a physical file on disk or a stream of data. |
| 54 | + |
| 55 | +``` csharp |
| 56 | +public record DownloadCustomersRequest(string FileName); |
| 57 | + |
| 58 | +internal class DownloadCustomersRequestValidator : AbstractValidator<DownloadCustomersRequest> |
| 59 | +{ |
| 60 | + public DownloadCustomersRequestValidator() |
| 61 | + { |
| 62 | + RuleFor(x => x.FileName) |
| 63 | + .NotEmpty() |
| 64 | + .Must(x => Path.GetExtension(x).Equals(".txt", StringComparison.OrdinalIgnoreCase)) |
| 65 | + .WithMessage("{PropertyName} must have .txt extension."); |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +[MapToGroup<CustomersV1RouteGroup>()] |
| 70 | +internal class DownloadCustomers(ServiceDbContext db) |
| 71 | + : MinimalEndpoint<DownloadCustomersRequest, IResult> |
| 72 | +{ |
| 73 | + protected override void Configure( |
| 74 | + IServiceProvider serviceProvider, |
| 75 | + IRouteGroupConfigurator? parentRouteGroup) |
| 76 | + { |
| 77 | + MapPost("/download/{FileName}"); |
| 78 | + } |
| 79 | + |
| 80 | + protected override async Task<IResult> HandleAsync( |
| 81 | + DownloadCustomersRequest req, |
| 82 | + CancellationToken ct) |
| 83 | + { |
| 84 | + await Task.CompletedTask; // Simulate some async work |
| 85 | + var customers = db.Customers.AsAsyncEnumerable(); |
| 86 | + return Results.Stream(async stream => |
| 87 | + { |
| 88 | + await foreach (var customer in customers.WithCancellation(ct)) |
| 89 | + { |
| 90 | + var line = $"{customer.Id},{customer.FirstName},{customer.MiddleName},{customer.LastName}\n"; |
| 91 | + var lineBytes = System.Text.Encoding.UTF8.GetBytes(line); |
| 92 | + await stream.WriteAsync(lineBytes, ct); |
| 93 | + } |
| 94 | + }, |
| 95 | + fileDownloadName: Path.GetFileName(req.FileName)); |
| 96 | + } |
| 97 | +} |
| 98 | +``` |
| 99 | +In this example, the `DownloadCustomers` endpoint returns a stream of customer data as a text file. The `Results.Stream()` method is used to write the data to the response stream, and the `fileDownloadName` parameter specifies the name of the file to be downloaded. |
0 commit comments