Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Datei Upload über eine Web-API
Duesmannr
myCSharp.de - Member



Dabei seit:
Beiträge: 145
Herkunft: Münster

Themenstarter:

Datei Upload über eine Web-API

beantworten | zitieren | melden

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
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Duesmannr am .
Attachments
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15944

beantworten | zitieren | melden

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 ;-)

- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
Duesmannr
myCSharp.de - Member



Dabei seit:
Beiträge: 145
Herkunft: Münster

Themenstarter:

beantworten | zitieren | melden

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

Morgen Abend gibts dann Rückmeldung
private Nachricht | Beiträge des Benutzers
Duesmannr
myCSharp.de - Member



Dabei seit:
Beiträge: 145
Herkunft: Münster

Themenstarter:

beantworten | zitieren | melden

Zitat von Abt
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.
Zitat von Abt
- 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?
Zitat von Abt
- Datenbank-Operationen darf man auch ruhig auslagern, muss man nich mit Logik mischen ;-)

Kommt

Aber danke für dein Feedback
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Duesmannr am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15944

beantworten | zitieren | melden

Zitat von Duesmannr
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
Zitat
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.
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
Duesmannr
myCSharp.de - Member



Dabei seit:
Beiträge: 145
Herkunft: Münster

Themenstarter:

beantworten | zitieren | melden

Ich nutze Streaming, wegen der Aussage von mir:
Zitat von Duesmannr
Der Upload soll gestreamt werden, weil Dateien von 0-20 GB übertragen werden.

Da werde ich IFormFile nicht verwenden
private Nachricht | Beiträge des Benutzers
Duesmannr
myCSharp.de - Member



Dabei seit:
Beiträge: 145
Herkunft: Münster

Themenstarter:

beantworten | zitieren | melden

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

Attachments
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15944

beantworten | zitieren | melden

Statt 8492734 Zeilen Exception Text und nem Bild wäre die Server-Antwort, die bemängelt wird, interessanter ;-)
Refit Handling Exceptions
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
Duesmannr
myCSharp.de - Member



Dabei seit:
Beiträge: 145
Herkunft: Münster

Themenstarter:

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15944

beantworten | zitieren | melden

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).
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
Duesmannr
myCSharp.de - Member



Dabei seit:
Beiträge: 145
Herkunft: Münster

Themenstarter:

beantworten | zitieren | melden

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

Mit deinem Link:
Zitat
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);

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Duesmannr am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15944

beantworten | zitieren | melden

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.
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
Duesmannr
myCSharp.de - Member



Dabei seit:
Beiträge: 145
Herkunft: Münster

Themenstarter:

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15944

beantworten | zitieren | melden

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

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
Duesmannr
myCSharp.de - Member



Dabei seit:
Beiträge: 145
Herkunft: Münster

Themenstarter:

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
Duesmannr
myCSharp.de - Member



Dabei seit:
Beiträge: 145
Herkunft: Münster

Themenstarter:

beantworten | zitieren | melden

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

Schönen Abend noch
private Nachricht | Beiträge des Benutzers
Duesmannr
myCSharp.de - Member



Dabei seit:
Beiträge: 145
Herkunft: Münster

Themenstarter:

beantworten | zitieren | melden

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.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von Duesmannr am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15944

beantworten | zitieren | melden

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.
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
Duesmannr
myCSharp.de - Member



Dabei seit:
Beiträge: 145
Herkunft: Münster

Themenstarter:

beantworten | zitieren | melden

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

Meinst du damit Blazor WebAssembly?
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15944

beantworten | zitieren | melden

Korrekt. Blazor WebAssembly ist die Bezeichnung für Blazor Client Side.
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
Duesmannr
myCSharp.de - Member



Dabei seit:
Beiträge: 145
Herkunft: Münster

Themenstarter:

beantworten | zitieren | melden

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

Es fliegt genau die gleiche Exception.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15944

beantworten | zitieren | melden

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..
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15944

beantworten | zitieren | melden

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();
    }
- performance is a feature -

Microsoft MVP - @Website - @blog - @AzureStuttgart - github.com/BenjaminAbt
private Nachricht | Beiträge des Benutzers
Duesmannr
myCSharp.de - Member



Dabei seit:
Beiträge: 145
Herkunft: Münster

Themenstarter:

beantworten | zitieren | melden

Zitat von Abt
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..

Hatte ich im nachhinein erstellt, weil die englische .NET Community nicht in diesem Forum vertreten ist.
Ist aber gelöscht.
Zitat von Abt
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.
private Nachricht | Beiträge des Benutzers