Skip to content

Server side Blazor + Paste large amount of text into text area with binding = Disconnection of client #5623

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
MarkStega opened this issue Oct 31, 2018 · 23 comments
Labels
affected-few This issue impacts only small number of customers area-blazor Includes: Blazor, Razor Components bug This issue describes a behavior which is not expected - a bug. feature-blazor-server feature-blazor-server-experience Issues that make Blazor server experience different of Web assembly or Desktop ✔️ Resolution: Duplicate Resolved as a duplicate of another issue investigate severity-major This label is used by an internal tool
Milestone

Comments

@MarkStega
Copy link

I have a server side execution Blazor app that is displaying a text area with a simple 'bind="@backingProperty"'. If I paste moderate amounts of text into the text area everything functions as it should. However, if I paste a large amount of text (it happens to be a base64 representation of an image in some html) then the connection is closed with the following error appearing:

Error: Connection disconnected with error 'Error: Server returned an error on close: Connection closed with an error.'. blazor.server.js:16:6839
	I</e.prototype.log https://localhost:44379/_framework/blazor.server.js:16:6839
	P</e.prototype.stopConnection/</< https://localhost:44379/_framework/blazor.server.js:16:27531
	a/</< https://localhost:44379/_framework/blazor.server.js:16:1652
	a/< https://localhost:44379/_framework/blazor.server.js:16:970
	s/< https://localhost:44379/_framework/blazor.server.js:16:697
	s https://localhost:44379/_framework/blazor.server.js:16:474
	P</e.prototype.stopConnection https://localhost:44379/_framework/blazor.server.js:16:27424
	P</e.prototype.startInternal/</</this.transport.onclose https://localhost:44379/_framework/blazor.server.js:16:23753
	U</e.prototype.connect/</</</i.onclose https://localhost:44379/_framework/blazor.server.js:16:20576

Blazor 0.6.0
Firefox 63.0
Window 10 Pro x64
IIS Express hosted server side Blazor
@danroth27
Copy link
Member

Do you see any exceptions in the logs on the server? You can check the server logs by selecting ASP.NET Core Web Server in the output tab in VS.

You might be hitting the default buffer size limit in SignalR. See https://github.com/aspnet/Blazor/issues/1614#issuecomment-433983017 for additional details.

@MarkStega
Copy link
Author

MarkStega commented Oct 31, 2018

There is a message in the server logs referring to an exception BackpressureDeadlock:

2018-10-31 13:37:54.9909|6|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager|Scanning connections. |url: |action: 
2018-10-31 13:37:54.9909|8|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager|Scanned connections in 00:00:00.0008526. |url: |action: 
2018-10-31 13:37:55.6296|9|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Message received. Type: Binary, size: 2048, EndOfMessage: False. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6296|9|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Message received. Type: Binary, size: 2048, EndOfMessage: False. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6319|9|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Message received. Type: Binary, size: 2048, EndOfMessage: False. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6319|9|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Message received. Type: Binary, size: 2048, EndOfMessage: False. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6319|9|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Message received. Type: Binary, size: 2048, EndOfMessage: False. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6319|9|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Message received. Type: Binary, size: 2048, EndOfMessage: False. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6319|9|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Message received. Type: Binary, size: 2048, EndOfMessage: False. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6319|9|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Message received. Type: Binary, size: 2048, EndOfMessage: False. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6319|9|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Message received. Type: Binary, size: 2048, EndOfMessage: False. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6319|9|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Message received. Type: Binary, size: 2048, EndOfMessage: False. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6319|9|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Message received. Type: Binary, size: 2048, EndOfMessage: False. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6319|9|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Message received. Type: Binary, size: 2048, EndOfMessage: False. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6319|9|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Message received. Type: Binary, size: 2048, EndOfMessage: False. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6319|9|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Message received. Type: Binary, size: 2048, EndOfMessage: False. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6319|9|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Message received. Type: Binary, size: 2048, EndOfMessage: False. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6319|9|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Message received. Type: Binary, size: 2048, EndOfMessage: False. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6319|2|ERROR|Microsoft.AspNetCore.SignalR.HubConnectionHandler|Error when processing requests. System.InvalidOperationException: Advancing examined to the end would cause pipe to deadlock because FlushAsync is waiting.
   at System.IO.Pipelines.ThrowHelper.ThrowInvalidOperationException_BackpressureDeadlock()
   at System.IO.Pipelines.Pipe.AdvanceReader(BufferSegment consumedSegment, Int32 consumedIndex, BufferSegment examinedSegment, Int32 examinedIndex)
   at System.IO.Pipelines.Pipe.AdvanceReader(SequencePosition& consumed, SequencePosition& examined)
   at System.IO.Pipelines.Pipe.DefaultPipeReader.AdvanceTo(SequencePosition consumed, SequencePosition examined)
   at Microsoft.AspNetCore.SignalR.HubConnectionHandler`1.DispatchMessagesAsync(HubConnectionContext connection)
   at Microsoft.AspNetCore.SignalR.HubConnectionHandler`1.RunHubAsync(HubConnectionContext connection)|url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6523|11|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Sending payload: 37 bytes. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6523|6|DEBUG|Microsoft.AspNetCore.SignalR.HubConnectionHandler|OnConnectedAsync ending. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6523|1|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionContext|Disposing connection TbfoNr4pa32HK3BjL98NKw. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6523|4|DEBUG|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Waiting for the application to finish sending data. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6523|6|DEBUG|Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets|Connection id "0HLHV9AQTL4T7" received FIN. |url: |action: 
2018-10-31 13:37:55.6523|2|DEBUG|Microsoft.AspNetCore.Http.Connections.Internal.Transports.WebSocketsTransport|Socket closed. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6523|4|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionContext|Waiting for WebSockets transport to complete. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6523|10|DEBUG|Microsoft.AspNetCore.Server.Kestrel|Connection id "0HLHV9AQTL4T7" disconnecting. |url: |action: 
2018-10-31 13:37:55.6523|5|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionContext|WebSockets transport complete. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6523|7|DEBUG|Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets|Connection id "0HLHV9AQTL4T7" sending FIN. |url: |action: 
2018-10-31 13:37:55.6523|2|DEBUG|Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager|Removing connection TbfoNr4pa32HK3BjL98NKw from the list of connections. |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6523|2|INFO|Microsoft.AspNetCore.Hosting.Internal.WebHost|Request finished in 106607.7491ms 101  |url: https://localhost/_blazor|action: 
2018-10-31 13:37:55.6523|2|DEBUG|Microsoft.AspNetCore.Server.Kestrel|Connection id "0HLHV9AQTL4T7" stopped. |url: |action: 
2018-10-31 13:37:55.9910|6|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager|Scanning connections. |url: |action: 
2018-10-31 13:37:55.9910|8|TRACE|Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager|Scanned connections in 00:00:00.0009206. |url: |action: 

Following the referenced issue with SignalR buffer size takes care of the issue, but shouldn't the implementation of the client 'chunk' a large buffer so as not to cause an overflow?

            app.UseSignalR(route => route.MapHub<BlazorHub>(BlazorHub.DefaultPath, o =>
            {
                o.ApplicationMaxBufferSize = 131072; // larger size
                o.TransportMaxBufferSize = 131072; // larger size
            }));
            app.UseBlazor<App.Startup>();

@danroth27
Copy link
Member

but shouldn't the implementation of the client 'chunk' a large buffer so as not to cause an overflow?

@anurse Thoughts on this?

@analogrelay
Copy link
Contributor

We don't automatically chunk. The streaming functionality makes it possible for users to chunk the data themselves, but we have no plans to automatically chunk data. SignalR isn't really well suited to sending large payloads.

@danroth27
Copy link
Member

@SteveSandersonMS @rynowak We should discuss if we want to do anything here beyond telling folks to increase the SignalR buffer sizes.

@Kaffeegangster
Copy link

i would appreciate if JSInterop would implement chunking on top of SignalR. Setting buffer size delays the problem but not solves it. The case where i needed to pass a string >32k i split it into substrings and called the interop function several times with the substrings and offsets. This works but it's not nice.

@MarkStega
Copy link
Author

I agree with @Kaffeegangster that setting a buffer size merely hides an implementation issue. After all, you can't predict what an end user is going to do when using an app.

@SteveSandersonMS
Copy link
Member

@danroth27 @rynowak I agree with @MarkStega that increasing the buffer size isn't really a proper solution. There's no scenario I can think of where you'd want there to be an arbitrary size limit on the diff. So, either Razor Components has to implement chunking on top of SignalR, or SignalR itself needs to.

I don't mind desperately either way, but since supporting that would benefit all SignalR apps, I think we should at least discuss a bit more with the SignalR folks if it would be viable as a future SignalR feature, otherwise the Razor Components implementation would be a standalone thing that doesn't benefit anyone else. CC @anurse @davidfowl.

@analogrelay
Copy link
Contributor

We've long avoided automatic chunking (in both ASP.NET and ASP.NET Core SignalR), I don't see it being a feature we intend to support. Besides, it's only possible for us to fix this at the Hub layer, and if you use ConnectionHandler you wouldn't benefit from any work we do there at all.

@SteveSandersonMS
Copy link
Member

@anurse Would it justify having some thin layer on top of ConnectionHandler that provides delivery of arbitrary-sized messages?

@analogrelay
Copy link
Contributor

Perhaps, but I don't think that would be a public API component. I could see building a shared-source component for this. I don't think we'd use it in SignalR as we haven't really seen demand for it at the Hub layer (since Hubs aren't really designed for large data anyway and have their own streaming primitives).

In 3.0 we currently plan to add the ability to "stream" data as a parameter (much like you can stream results) which might also help here, but again, only for the Hub layer.

@davidfowl
Copy link
Member

I don’t quite understand the chunking request, are you asking for streaming? The limit is about total buffered memory so this needs to be implemented in the app layer.

@SteveSandersonMS
Copy link
Member

@davidfowl I haven't reproduced the issue so I'm not certain what the ideal resolution would be.

I think what we need for sure is the ability for the server to dispatch an arbitrarily large message to the client, since the render tree diff could be arbitrarily large. Streaming may not be relevant, since the server already has the data in a buffer in memory.

On the other hand, we don't necessarily need to let the client send an arbitrarily large message to the server. I'm aware that if we do, then there are DOS concerns since the server would need to allocate a correspondingly-sized buffer (and there's no equivalent DOS scenario in the server->client direction).

Perhaps there isn't any problem to solve here, other than possibly implementing JS interop support for streams at some point in the future. The only short-term problem is if the server->client direction has arbitrary size limits despite the data already being in some byte[] in server memory.

@Kaffeegangster
Copy link

For my use case i need to send a bigger (a few 100 kb) string (xml) from the server->client and later back from client->server to save it in a database.
Just in case JS Interop supports a SignalR ChannelReader in the future a pipe with ChannelWriter back to the server could be usefull.
The SignalR AdvanceReader Exception is easy to reproduce if you call the public static Task Prompt(string message) from the blazorlib template with a message size >32k

@SteveSandersonMS
Copy link
Member

@Kaffeegangster I agree that support for streaming would be valuable. I think that's the right solution for sending arbitrarily large amounts of data from client to server. We wouldn't implement a non-streaming way to send arbitrarily large blocks of data, because that would be a DOS risk to the server.

@agonzalezm
Copy link

I am also seeing this error if I put 31085 chars in a textarea with a bind property in blazor server-side. If i put 31084 chars it works, anything higher i see the same error.

31085 chars is not much, if you write a blog article in a textarea it will exceed that probably.

Any solution or workaround for that?

@MarkStega
Copy link
Author

@agonzalezm @danroth27

The reference in Dan's post right after the first post "( See #1614 fo additional details.)" for a short term work-around for this implementation issue.

@aspnet-hello aspnet-hello transferred this issue from dotnet/blazor Dec 17, 2018
@aspnet-hello aspnet-hello added area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates area-blazor Includes: Blazor, Razor Components labels Dec 17, 2018
@mkArtakMSFT mkArtakMSFT added the Needs: Design This issue requires design work before implementating. label Apr 17, 2019
@mkArtakMSFT mkArtakMSFT added this to the 3.0.0-preview7 milestone Apr 17, 2019
@mkArtakMSFT mkArtakMSFT removed area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates labels May 9, 2019
@mkArtakMSFT mkArtakMSFT modified the milestones: 3.0.0-preview7, Backlog May 28, 2019
@Styx8888
Copy link

How to do it using .netcore 3.0 and blazor ?

Is there any workaround for this using .net core 3.0 ?
I tried something like below, but it is not working:

app.UseEndpoints(endpoints => {
endpoints.MapBlazorHub(o =>
{
o.ApplicationMaxBufferSize = 92233720; // larger size
o.TransportMaxBufferSize = 92233720; // larger size
});

                       endpoints.MapFallbackToPage("/_Host");
    });

@tarek1243
Copy link

had the same issue
adding this to the startup fixed it for me

using Microsoft.AspNetCore.SignalR;
..........
///increase size of textarea accepted value value
services.Configure(options =>
{
options.MaximumReceiveMessageSize = null;
});

@JvanderStad
Copy link

I am also seeing this error if I put 31085 chars in a textarea with a bind property in blazor server-side. If i put 31084 chars it works, anything higher i see the same error.

31085 chars is not much, if you write a blog article in a textarea it will exceed that probably.

Any solution or workaround for that?

Max size I can paste is 16290 chars.

@JvanderStad
Copy link

JvanderStad commented Jul 20, 2020

This fixed my problem:

services
	.AddServerSideBlazor()
	.AddHubOptions(x => x.MaximumReceiveMessageSize = 102400000);

@SteveSandersonMS SteveSandersonMS added affected-few This issue impacts only small number of customers bug This issue describes a behavior which is not expected - a bug. severity-major This label is used by an internal tool labels Oct 6, 2020 — with ASP.NET Core Issue Ranking
@Aculeo
Copy link

Aculeo commented Oct 27, 2020

Can confirm the comment above worked for me as well. This seems like a pretty big issue.

I have a razor page with a decently long table (79 rows), and for each row I added a razor component, this was enough to make the request 33KB and I got this error, took me an hour to figure out what is happening (initially thought my component was broken).

@TanayParikh
Copy link
Contributor

Hello, thanks for contacting us. This issue was also discussed as part of #30291, and we added a sample app to document working with large text areas in Blazor:

https://github.com/aspnet/samples/tree/main/samples/aspnetcore/blazor/InputLargeTextArea

@TanayParikh TanayParikh added the ✔️ Resolution: Duplicate Resolved as a duplicate of another issue label Nov 5, 2021
@ghost ghost added the Status: Resolved label Nov 5, 2021
@TanayParikh TanayParikh removed Needs: Design This issue requires design work before implementating. Status: Resolved labels Nov 5, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Dec 5, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affected-few This issue impacts only small number of customers area-blazor Includes: Blazor, Razor Components bug This issue describes a behavior which is not expected - a bug. feature-blazor-server feature-blazor-server-experience Issues that make Blazor server experience different of Web assembly or Desktop ✔️ Resolution: Duplicate Resolved as a duplicate of another issue investigate severity-major This label is used by an internal tool
Projects
None yet
Development

No branches or pull requests