I'm currently trying to create an Aspire based project where, among other things, you can upload files to a MinIO backend. In order to somewhat minimize the shoving around of files, I'm trying to upload user files directly from the Web Client to MinIO.
The flow is as follows:
- The Blazor Client gets a presigned MinIO url for upload in order to not expose the credentials for the bucket
- The user selects a file and the Blazor Client reads it as a StreamContent.
- The HttpClient then PUTs the file as a stream to the MinIO instance
The presigned MinIO url works and I can upload files using Postman just fine. Reading the file also works. It's when it comes to step 3 that things go wrong. I'm always getting an exception like this:
System.Net.Http.HttpRequestException: Error while copying content to a stream. ---> System.IO.IOException: Unable to write data to the transport connection: An existing connection was closed by the remote host..This is the code in question:
@page "/fileupload"@using System.Linq@using System.Net.Http.Headers@inject MinIOClient client@inject ILogger<FileUpload> Logger@inject HttpClient httpClient@rendermode InteractiveServer<PageTitle>File Upload 2</PageTitle><h1>File Upload Example 2</h1><p><label> Upload <InputFile OnChange="OnInputFileChange" /></label></p>@if (file != null){<div class="card"><div class="card-body"><ul><li> File: @file.Name<br> @if (FileUploadResults(uploadResult, file.Name, Logger, out var result)) {<span> Stored File Name: @result.StoredFileName</span> } else {<span> There was an error uploading the file (Error: @result.ErrorCode).</span> }</li></ul></div></div>}@code { private File? file; private UploadResult uploadResult = new(); private bool shouldRender; string url = string.Empty; protected override bool ShouldRender() => shouldRender; private async Task OnInputFileChange(InputFileChangeEventArgs e) { shouldRender = false; long maxFileSize = 1024 * 1024 * 1024; var selectedFile = e.File; if (selectedFile != null) { try { file = new() { Name = selectedFile.Name }; //This gets the presigned MinIO url var resp = await client.GetUrl(); if (resp is null) return; using var content = new MultipartFormDataContent(); var fileContent = new StreamContent(selectedFile.OpenReadStream(maxFileSize)); fileContent.Headers.ContentType = new MediaTypeHeaderValue(selectedFile.ContentType); content.Add(content: fileContent, name: "\"file\"", fileName: selectedFile.Name); var response = await httpClient.PutAsync(resp, content); // Assuming the response contains the upload result // Update the uploadResult based on the response // For example: // uploadResult = await response.Content.ReadFromJsonAsync<UploadResult>(); // Simulate a successful upload result for demonstration uploadResult = new UploadResult { FileName = selectedFile.Name, StoredFileName = "stored_" + selectedFile.Name, Uploaded = true }; } catch (Exception ex) { Logger.LogInformation("{FileName} not uploaded (Err: 6): {Message}", selectedFile.Name, ex.Message); uploadResult = new UploadResult { FileName = selectedFile.Name, ErrorCode = 6, Uploaded = false }; } } shouldRender = true; } private static bool FileUploadResults(UploadResult uploadResult, string? fileName, ILogger<FileUpload> logger, out UploadResult result) { result = uploadResult; if (!result.Uploaded) { logger.LogInformation("{FileName} not uploaded (Err: 5)", fileName); result.ErrorCode = 5; } return result.Uploaded; } private class File { public string? Name { get; set; } } private class UploadResult { public string? FileName { get; set; } public string? StoredFileName { get; set; } public bool Uploaded { get; set; } public int ErrorCode { get; set; } }}Already tried several variants but they all yield the same error...