Laden...

Datei Upload über eine Web-API

Erstellt von Duesmannr vor 2 Jahren Letzter Beitrag vor 2 Jahren 1.270 Views
D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 2 Jahren
Datei Upload über eine Web-API

Nabend,

Ausgangslage:
Asp.Net Core WEB API .NET 5
Blazor Server-Side .NET 5

Ich habe eine Controller Methode die den Upload verwaltet, was ich durch diese Seite realisiert habe.

Der Upload soll gestreamt werden, weil Dateien von 0-20 GB übertragen werden.

Mein Code sieht so aus:


[HttpPost]
        [DisableRequestSizeLimit]
        public async Task<IActionResult> UploadFileAsync()
        {
            if (!MultipartRequestHelper.IsMultipartContentType(this.Request.ContentType))
            {
                this.ModelState.AddModelError("File", "The request couldn't be processed (Error 1).");

                return this.BadRequest(this.ModelState);
            }

            string boundary = MultipartRequestHelper.GetBoundary(
                MediaTypeHeaderValue.Parse(this.Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit);

            MultipartReader reader = new(boundary, this.HttpContext.Request.Body);

            MultipartSection section = await reader.ReadNextSectionAsync();

            while (section != null)
            {
                bool hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(
                section.ContentDisposition, out ContentDispositionHeaderValue contentDisposition);

                if (hasContentDispositionHeader)
                {
                    if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition))
                    {
                        try
                        {
                            await this._fileBLL.UploadFileAsync(section, contentDisposition);
                        }
                        catch (Exception ex)
                        {
                            this.ModelState.AddModelError("Processing", ex.ToString());
                        }
                    }
                    else
                    {
                        this.ModelState.AddModelError("File", "The request couldn't be processed (Error 2).");
                    }
                }

                section = await reader.ReadNextSectionAsync();
            }

            return this.Ok(this.ModelState);
        }

Die UploadFileAsync BLL Methode ist diese hier


public async Task UploadFileAsync(MultipartSection section, ContentDispositionHeaderValue contentDisposition)
        {
            string trustedFileName = WebUtility.HtmlEncode(contentDisposition.FileName.Value);

            IMongoDatabase mongoDatabase = this._mongoClient.GetDatabase(this._mongo_DatabaseName);

            GridFSBucket bucket = new(mongoDatabase, new()
            {
                BucketName = this._mongo_CollectionName,
                ChunkSizeBytes = this._mongo_ChunkSizeBytesLength
            });

            Guid videoId = Guid.NewGuid();

            using GridFSUploadStream uploadStream = await bucket.OpenUploadStreamAsync(trustedFileName, new()
            {
                Metadata = new()
                {
                    { "Id", videoId.ToStringValue() }
                }
            });

            int bytesRead = 0;
            byte[] buffer = new byte[8192];

            while ((bytesRead = await section.Body.ReadAsync(buffer.AsMemory(0, buffer.Length))) != 0)
            {
                await uploadStream.WriteAsync(buffer.AsMemory(0, bytesRead));
            }

            await uploadStream.CloseAsync();
            await section.Body.DisposeAsync();
        }

Mit Postman (Foto im Anhang) funktioniert der Upload einwandfrei und die Datei wird in die MongoDB geschrieben.

Das ganze will ich nun auch mit der Blazor Server-Side App realisieren.
Dafür habe ich den Code


public async Task UploadFileAsync(IBrowserFile browserFile)
        {
            HttpRequestMessage requestMessage = new(HttpMethod.Post, "api/v1/File");

            MultipartFormDataContent multipartFormDataContent = new();
            multipartFormDataContent.Add(new StreamContent(browserFile.OpenReadStream(long.MaxValue)), 
                browserFile.Name, browserFile.Name);

            //requestMessage.Content = multipartFormDataContent;

            //HttpResponseMessage response = await this._client.SendAsync(requestMessage);
            HttpResponseMessage response = await this._client.PostAsync("api/v1/File", multipartFormDataContent);

            if (response.IsSuccessStatusCode)
            {
                string responseString = await response.Content.ReadAsStringAsync();
            }
        }


IBrowserFile browserFile

kommt von der UI:


<input type="file" multiple />

Das ganze funktioniert nur bedingt.
Der Code-Block der nicht ausgeführt wird auf diesem Weg ist der:


int bytesRead = 0;
            byte[] buffer = new byte[8192];

            while ((bytesRead = await section.Body.ReadAsync(buffer.AsMemory(0, buffer.Length))) != 0)
            {
                await uploadStream.WriteAsync(buffer.AsMemory(0, bytesRead));
            }

            await uploadStream.CloseAsync();
            await section.Body.DisposeAsync();

Er überspringt die while Schleife, weil der Body anscheinend leer ist.

Aber was mache ich beim Post Request falsch? Durch googlen bin ich bis jetzt auch nicht schlauer geworden.
Ob ich HttpClient.PostAsync oder HttpClient.SendAsync aufrufe, ändert nichts.

Habt Ihr Anregungen?

Grüße und einen schönen Abend 🙂

16.807 Beiträge seit 2008
vor 2 Jahren

Mach Dir selbst nen SDK Deiner API durch Refit. So musst Du den ganzen File HTTP Quark nicht selbst schreiben.
reactiveui/refit

Hast dann am Ende nur


public interface MyAPI
{
    [Multipart]
    [Post("/myfile/upload")]
    Task UploadImages([AliasAs("files")] IEnumerable<StreamPart> streams);
}

Genaue Doku sieh reactiveui/refit

Auf der Server-Seite brauchst Du dann nur ein Multipart Upload Action.
Brauchst keine 20 Zeilen dank Refit dafür.

Aber Feedback zum Code:

  • Du hast viel obsolete Code vermutlich aus verschiedenen Quellen zusammenkopiert, selbst die Error Code haste übernommen (???)
  • Man sollte IFormFile verwenden
  • Schichtentrennung darf man ruhig machen, tut nicht weh [Artikel] Drei-Schichten-Architektur
  • Datenbank-Operationen darf man auch ruhig auslagern, muss man nich mit Logik mischen 😉
D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 2 Jahren

Ich werde es mal einbauen und dann gucken ob es funktioniert.

Morgen Abend gibts dann Rückmeldung 🙂

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 2 Jahren

Aber Feedback zum Code:

  • Du hast viel obsolete Code vermutlich aus verschiedenen Quellen zusammenkopiert, selbst die Error Code haste übernommen (???)

Stimmt. Derzeit aber nur zum testen, bis es funktioniert, danach wird der Code deutlich verbessert.

  • Man sollte IFormFile verwenden

Warum? Werden die Files dann nicht im Arbeitsspeicher zwischen gespeichert? Warum nutzt die Microsoft Doku das ebenfalls nicht um große Dateien hochzuladen?

  • Datenbank-Operationen darf man auch ruhig auslagern, muss man nich mit Logik mischen 😉

Kommt 🙂

Aber danke für dein Feedback 🙂

16.807 Beiträge seit 2008
vor 2 Jahren

Warum? Werden die Files dann nicht im Arbeitsspeicher zwischen gespeichert? Warum nutzt die Microsoft Doku das ebenfalls nicht um große Dateien hochzuladen? Hochladen von Dateien in ASP.NET Core - IFormFile
Welche Ressourcen (Datenträger, Arbeitsspeicher) für das Hochladen von Dateien verwendet werden, ist von der Anzahl und Größe gleichzeitig hochgeladener Dateien abhängig. Wenn eine App versucht, zu viele Uploads zu puffern, stürzt die Website ab, sobald der Arbeitsspeicher oder Speicherplatz auf dem Datenträger ausgelastet ist.

Aber okay, wenn ich Dich richtig verstehe, dann willst Du bewusst Streaming verwenden.
Das hab ich zuerst übersehen.

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 2 Jahren

Ich nutze Streaming, wegen der Aussage von mir:

Der Upload soll gestreamt werden, weil Dateien von 0-20 GB übertragen werden.

Da werde ich IFormFile nicht verwenden 🙂

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 2 Jahren

Da melde ich mich wieder.

[Blazor App]
Refit installiert, Interface erstellt, Services hinzugefügt => Exception.

[Console App]
Copy Paste => Funktioniert. (Lokale Datei, 8.7GB)

Hier ist einmal das Interface


public interface IFileApi
    {
        [Multipart]
        [Post("/api/v1/File")]
        Task<HttpResponseMessage> UploadFileAsync(StreamPart streamPart);
    }

So registriere ich die Services in der Startup Klasse


services.AddRefitClient<IFileApi>()
                .ConfigureHttpClient(c => c.BaseAddress = new Uri(apiBaseAddress)); //apiBaseAddress = https://localhost:5003/

In der Razor Datei injecte ich das Interface, iteriere durch die IBrowserFiles und rufe die Methode auf.


foreach (IBrowserFile file in this._selectedFiles)
        {
            try
            {
                StreamPart streamPart = new(file.OpenReadStream(long.MaxValue), file.Name);

                var res1 = await this.FileApi.UploadFileAsync(streamPart);
            }
            catch (Exception ex)
            { }
        }

Lande im Catch. Siehe UI Info im Anhang. Und aus dem Stacktrace, kann ich nicht erkennen, woran es liegt.
Ich denke es liegt an dem IBrowserFile Interface bzw. der OpenReadStream Methode die aufgerufen wird.
Die Datei die hochgeladen wurde, war 8,7GB groß. Eine TextDatei von 0 Bytes konnte ich ohne Probleme hochladen bzw. ist der Call zur API durch gegangen.
Aber woran kann es liegen?

Hier noch einmal der Stacktrace von der Exception:


   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at Microsoft.AspNetCore.Components.Forms.RemoteBrowserFileStream.<FillBuffer>d__9.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.IO.Pipelines.PipeCompletion.ThrowLatchedException()
   at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result)
   at System.IO.Pipelines.Pipe.ReadAsync(CancellationToken token)
   at System.IO.Pipelines.Pipe.DefaultPipeReader.ReadAsync(CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Components.Forms.RemoteBrowserFileStream.<CopyFileDataIntoBuffer>d__10.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
   at Microsoft.AspNetCore.Components.Forms.BrowserFileStream.<ReadAsync>d__22.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.IO.Stream.<CopyToAsyncInternal>d__29.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Net.Http.HttpContent.<<CopyToAsync>g__WaitAsync|56_0>d.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Net.Http.MultipartContent.<SerializeToStreamAsyncCore>d__23.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Net.Http.HttpContent.<<CopyToAsync>g__WaitAsync|56_0>d.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Net.Http.HttpConnection.<SendRequestContentAsync>d__62.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Net.Http.HttpConnection.<SendAsyncCore>d__56.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Net.Http.HttpConnection.<SendAsyncCore>d__56.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at System.Net.Http.HttpConnectionPool.<SendWithRetryAsync>d__72.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable`1.ConfiguredValueTaskAwaiter.GetResult()
   at System.Net.Http.RedirectHandler.<SendAsync>d__4.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at System.Net.Http.DiagnosticsHandler.<SendAsyncCore>d__5.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.Extensions.Http.Logging.LoggingHttpMessageHandler.<SendAsync>d__5.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.<SendAsync>d__5.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at System.Net.Http.HttpClient.<SendAsyncCore>d__85.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Refit.RequestBuilderImplementation.<>c__DisplayClass14_0`2.<<BuildCancellableTaskFuncForMethod>b__0>d.MoveNext() in /_/Refit/RequestBuilderImplementation.cs:line 296
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at RD.Intelligence.Web.Components.AddFilesComponent.<UploadFilesAsync>d__14.MoveNext() in D:\Repositories\RD.Intelligence\RD.Intelligence.Web\Components\AddFilesComponent.razor:line 87

16.807 Beiträge seit 2008
vor 2 Jahren

Statt 8492734 Zeilen Exception Text und nem Bild wäre die Server-Antwort, die bemängelt wird, interessanter 😉Refit Handling Exceptions

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 2 Jahren

Da stimme ich dir zu.
Nur komme ich gar nicht bis zur API Methode.
Die wird quasi nicht ausgeführt und hab daher auch keine Response vom Server.

16.807 Beiträge seit 2008
vor 2 Jahren

Dann find mal raus, welche Zeile wirklich knallt. Kann auch die Blazor Komponente sein.
Sonst raten wir hier nur.


StreamPart streamPart = new(file.OpenReadStream(long.MaxValue), file.Name);

Bin mir nicht sicher, ob das vielleicht ein Dont ist.ASP.NET Core Blazor-Dateiuploads

Hab leider kein Zugriff mehr auf den Kunden-Code den ich so mit Blazor und Refit gemacht hab.
Waren Dateien bis 5 GB - und das ging am Ende problemlos (ebenfalls Streaming).

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 2 Jahren

Wie ich es herausfinden soll, stellt mich gerade auf die Probe.

Mit deinem Link:

Der folgende Ansatz wird für Microsoft Azure Blob Storage empfohlen, da die Stream-Klasse der Datei direkt für UploadBlobAsync bereitgestellt wird:

Das ganze will ich ja auch und mache ich eig. ja auch. Nur das es nicht Azure ist.

Edit:
Selbst wenn ich den StreamPart von Refit weg lasse, bekomme ich das gleiche Ergebnis.


Stream stream = file.OpenReadStream(long.MaxValue);

response = await this.FileApi.UploadFileAsync2(stream);

16.807 Beiträge seit 2008
vor 2 Jahren

Vielleicht gibts bei Blazor Server Side hier eine Besonderheit, die ich auch noch nicht kenne.
Das allgemeine Kommunikationsmodell ist hier ja anders als bei Client Side Blazor.

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 2 Jahren

Dann erstelle ich mal ein Github Issue.

Habe jetzt mal mehrere Dateien getestet.

3,56GB => Kommt an, kann aber nichts von gelesen werden (die while Schleife wird übersprungen)
über 2GB gleiches Verhalten.

Unter 2 GB => Kommt ebenfalls an, aber der Content von der Datei kann auch gelesen werden.

16.807 Beiträge seit 2008
vor 2 Jahren

Ich könnte mir vorstellen, da Blazor Server Side über SignalR kommuniziert, Du hier in ein Limit laufen könntest.

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 2 Jahren

Dann dürfte es laut einem Github Issue eine Fehlermeldung seitens SignalR werfen.

Aber auch mit


services.Configure<HubOptions>(options =>
            {
                options.MaximumReceiveMessageSize = null;
            });

Was mit Workaround in dem Issue gemeint ist, ändert es nichts.

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 2 Jahren

Issue ist erstellt.
Sollte was dabei raus kommen, werde ich die Lösung hier bekannt geben.

Schönen Abend noch 🙂

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 2 Jahren

Nabend,

zur Info, dass Github Issue wurde ins Backlog verschoben.
Falls da was neues kommen sollte, sag ich hier Bescheid.

Dann dachte ich, löse ich das nicht über Streaming der ganzen Datei, sondern transferiere die Datei in Chunks.


buffer = new byte[8120];
using Stream stream = file.OpenReadStream(long.MaxValue); //file = IBrowserFile vom <InputFile> Element
await stream.ReadAsync(buffer, 0, buffer.Length);

Der Code-Schnipsel sorgt ebenfalls für die gleiche Exception. (3. Zeile)
Also gibt es derzeit mit der Blazor Componente keine Möglichkeit, Dateien über 2? GB zu handlen.
Für meinen Test war es eine Datei mit 9,7 GB.

Werde das ganze über Plain JS lösen, weil da funktioniert das..

Grüße

Edit:
Habe gerade nochmal gegooglet und spontan vom 15.11.2020 das Github Issue gefunden. Gleicher Fehler, ist aber auch nicht gefixt.

16.807 Beiträge seit 2008
vor 2 Jahren

Vor allem dem zweiten Issue entnehme ich, dass meine Vermutung, dass Du in ein Websocket-Limit läufst, richtig sein wird.
Die Datei wird nämlich nicht vom Client zur API geschickt, sondern erst vom Client zur Server App und dann erst zur API.
Dass JS funktioniert, weil Du damit den Socket umgehst: klar.

Blazor Server ist eine gute Idee als Übergangslösung - und so ist sie auch gedacht und sollte verwendet werden. Sie deckt aber bei weitem nicht alle Client-Szenarien ab.
Sieht man im Endeffekt auch am Markt: alle, die können, setzen bereits auf den Client.

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 2 Jahren

Sieht man im Endeffekt auch am Markt: alle, die können, setzen bereits auf den Client.

Meinst du damit Blazor WebAssembly?

16.807 Beiträge seit 2008
vor 2 Jahren

Korrekt. Blazor WebAssembly ist die Bezeichnung für Blazor Client Side.

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 2 Jahren

Ich habe den Upload auch gerade nochmal mit Blazor WebAssembly versucht.

Es fliegt genau die gleiche Exception.

16.807 Beiträge seit 2008
vor 2 Jahren

Schade, dass uns andere statt Du den Hinweis gegeben haben, dass Du das Thema auch noch wo anders veröffentlich hast 🙂unable-to-upload-files-that-are-larger-than-2-gb-to-web-api-blazor-server-side

Nicht nett -> [Hinweis] Wie poste ich richtig? 2.2 Keine Crossposts
Ebenso verstößt Du damit den Regeln von Stackoverflow..

16.807 Beiträge seit 2008
vor 2 Jahren

Ich hab mir mal angeschaut, warum das in JavaScript funktioniert aber in der WebAssembly nicht, sofern man das über eigenen Code lösen will.
Denn ein stupides HTML-Formular funktioniert problemlos.

Der Fehler taucht nicht bei OpenReadStream auf, sondern bei der Verarbeitung des Buffers im HTTP Client.
Dadurch hab ich mir durchgelesen, wie das aktuell funktioniert; und es ist wohl so, dass es derzeit keine Streaming Möglichkeit von WebAssembly gibt (egal ob Blazor oder was anderes).
https://github.com/dotnet/aspnetcore/issues/31873
Javier Nelson schreibt, dass dies mit Chrome 87 in die Testphase kam - aber ich sehe nirgends, dass es mittlerweile im Release ist.
Auch die entsprechenden Chrome Flags enable-experimental-webassembly-features geben keine Hinweise dazu.
Der aktuelle MemoryLeak in diesem Fall hat bei mir übrigens zum Bluescreen geführt..

D.h. sofern die jeweiligen Browser entsprechendes nicht unterstützen, dann wirds auch nichts mit WebAssembly Streaming in Blazor.
Dass JavaScript funkioniert liegt eben an a) Bypass vom Socket (weil hier auch gebuffert wird) und b) Bypass dieser Limits.

Die minimalistischste Variante ohne Refit zur Nachvollziehbarkeit ist:


    private async Task UploadFile(InputFileChangeEventArgs e)
    {
            HttpClient httpClient = new HttpClient();

            var stream = e.File.OpenReadStream(long.MaxValue);
            var content = new MultipartFormDataContent();

            content.Add(new StreamContent(stream), e.File.Name);

            HttpResponseMessage response =
                await httpClient.PostAsync("https://localhost:5001/filestreamtest", content);

            response.Dispose();
    }

D
Duesmannr Themenstarter:in
161 Beiträge seit 2017
vor 2 Jahren

Schade, dass uns andere statt Du den Hinweis gegeben haben, dass Du das Thema auch noch wo anders veröffentlich hast 🙂
>

Nicht nett ->
>
2.2 Keine Crossposts
Ebenso verstößt Du damit den Regeln von Stackoverflow..

Hatte ich im nachhinein erstellt, weil die englische .NET Community nicht in diesem Forum vertreten ist.
Ist aber gelöscht.

Dadurch hab ich mir durchgelesen, wie das aktuell funktioniert; und es ist wohl so, dass es derzeit keine Streaming Möglichkeit von WebAssembly gibt (egal ob Blazor oder was anderes).

Ja läuft^^
Wie erwähnt, habe ich das dann mit Javascript umgesetzt.