如何在.NET客户端通过SignalR发送大数据

18
我们有一个使用SignalR调用服务器方法的.NET客户端,但参数似乎非常大,对于这种情况该怎么解决呢?
客户端代码:
public async Task FooAsync()
{
    var hubConnection = new HubConnection(...);
    await hubConnection.Start();

    var hubProxy = hubConnection.CreateHubProcx("ValueHub");
    //the content is very long, about 11776065 bytes (11MB)
    var content = File.ReadAllText(...);
    hubProxy.Invoke("Send", content);
    ...
}

服务器代码:

[HubName("ValueHub")]
public class ValueHub : Hub
{
    public void Send(string json)
    {

    }
}

从异常堆栈和源代码中,我发现SignalR内部使用HttpClientFormUrlEncodedContent类型的HttpContent,也许限制就来自于此。

System.UriFormatException was unhandled
  HResult=-2146233033
  Message=Invalid URI: The Uri string is too long.
  Source=System
  StackTrace:
       at System.UriHelper.EscapeString(String input, Int32 start, Int32 end, Char[] dest, Int32& destPos, Boolean isUriString, Char force1, Char force2, Char rsvd)
       at System.Uri.EscapeDataString(String stringToEscape)
       at System.Net.Http.FormUrlEncodedContent.Encode(String data)
       at System.Net.Http.FormUrlEncodedContent.GetContentByteArray(IEnumerable`1 nameValueCollection)
       at System.Net.Http.FormUrlEncodedContent..ctor(IEnumerable`1 nameValueCollection)
       at Microsoft.AspNet.SignalR.Client.Http.DefaultHttpClient.Post(String url, Action`1 prepareRequest, IDictionary`2 postData, Boolean isLongRunning)
       at Microsoft.AspNet.SignalR.Client.Transports.HttpBasedTransport.Send(IConnection connection, String data, String connectionData)
       at Microsoft.AspNet.SignalR.Client.Transports.AutoTransport.Send(IConnection connection, String data, String connectionData)
       at Microsoft.AspNet.SignalR.Client.Connection.Send(String data)
       at Microsoft.AspNet.SignalR.Client.Hubs.HubProxy.Invoke[T](String method, Object[] args)
       at Microsoft.AspNet.SignalR.Client.Hubs.HubProxy.Invoke(String method, Object[] args)

有没有关于这个问题的好建议?

4
说实话,我不会在中心枢纽(hub)中这样做。可以使用中心枢纽作为消息框架来通知客户端有新数据到达,然后客户端可以通过Web API / WebMethod或任何其他传输技术获取数据。 - Schadensbegrenzer
这可能会对你有所帮助 https://dev59.com/k2w05IYBdhLWcg3wxUj_ - K D
使用案例是什么? - Anders
https://dev59.com/92rXa4cB1Zd3GeqPEfas - st4hoo
4个回答

22

您可以通过将MaxIncomingWebSocketMessageSize设置为null,在Startup.cs中添加一行代码,使消息大小变为“无限制”:

    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
        app.MapSignalR();
        GlobalHost.Configuration.MaxIncomingWebSocketMessageSize = null;
        }
    }
} 

我的工作需要处理大约200kb的数据,能够稳定地发送10条消息。尽管如此,如果每秒发送更多的数据,我不知道它是否能够良好地运行。


1
工作得很好。不错的解决方案。 - No1Lives4Ever
没对我起作用。可能是因为它是一个使用Web Api和Signalr的owin应用程序,所以配置必须设置得不同。 - Christoph Adamakis
1
如果SignalR在Owin应用程序中,则必须结合使用此http://jerodkrone.com/signalr-2-0-dependency-injection-using-globalhost/ 来处理上面的答案。因此,如果hub正在使用自定义配置(例如var hubconfig = new HubConfiguration();)和自定义解析器(例如hubconfig.Resolver = new AutofacDependencyResolver(lifetimeScope);),则需要在StartUp中添加以下2行: GlobalHost.DependencyResolver = hubconfig.Resolver; GlobalHost.Configuration.MaxIncomingWebSocketMessageSize = null; - Christoph Adamakis
1

对于 .NET Core 使用 -

  • services.AddSignalR(configure => { configure.MaximumReceiveMessageSize = null; });
- Muhammad Waqas Aziz
1
这真的应该成为被接受的答案。它解决了我的问题。非常感谢@Alexander,我为此苦恼了很久! - David R.

8

正如您已经了解的那样,这些数据对于SIGNALR的设计来说太多了。

也许更好的做法是使用另一个进程通过普通的REST API(GET / POST)来处理这些数据。或者向用户发送一条消息,表明需要执行此操作,因为这感觉非常“批量”。

其次,如果这是必需的(可能不适合该工具),您是否考虑过压��。


小文件怎么办?我想发送60KB的缩略图。我可以告诉我的服务器接受这样长的查询字符串(而且速度还相当快),但是SignalR的URI编码仍然会阻塞它:S。 - tec-goblin

6

its easy to do it..

  • split files into byte Array chunks (my tests shows max 10kb per chunk is enough)
  • send chunks to client with an invoke like (calculate totalBytes and the chunk data you have) :

    hubProxy.Invoke("Send", chunk,currentBytes,totalBytes);
    
  • get the chunks from client and create a byte array and append each chunk, signalr sends files syncronously, this means data will be received as your send order
  • you have totalbytes and currentBytes data, now you know all data received, save this byte array to a file with stream or whatever you like..

3
您需要将序列信息与其一起发送,因为我读到SignalR不能保证消息的顺序。 - TheLegendaryCopyCoder
可能发送流位置号可以为每个块定义序列信息。 - Mustafa Salih ASLIM

3

请将以下代码添加到 Web.config 文件中:
<httpRuntime maxRequestLength="1048576" executionTimeout="600" />

然后将以下代码添加到 Startup.cs 文件中:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.MapSignalR();
        GlobalHost.Configuration.MaxIncomingWebSocketMessageSize = null;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接