SignalR 必须使用适当的 属性 或方法修改 'User-Agent' header

SignalR The 'User-Agent' header must be modified using the appropriate property or method

我有 C# .NET Framework SignalR 客户端应用程序和 ASP.NET Core 2.1 服务器。当我尝试通过 WebSockets 开始连接到 SignalR Hub 时,出现异常。

System.AggregateException: Unable to connect to the server with any of the available transports.
 
--->
Microsoft.AspNetCore.Http.Connections.Client.TransportFailedException: WebSockets failed: The 'User-Agent' header must be modified using the appropriate property or method. Имя параметра: name
 
    --->
    System.ArgumentException: The 'User-Agent' header must be modified using the appropriate property or method. Parameter name: name

        in System.Net.WebHeaderCollection.ThrowOnRestrictedHeader(String headerName)
        in System.Net.WebHeaderCollection.Set(String name, String value)
        in Microsoft.AspNetCore.Http.Connections.Client.Internal.WebSocketsTransport..ctor(HttpConnectionOptions httpConnectionOptions, ILoggerFactory loggerFactory, Func`1 accessTokenProvider)
        in Microsoft.AspNetCore.Http.Connections.Client.Internal.DefaultTransportFactory.CreateTransport(HttpTransportType availableServerTransports)
        in Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.<StartTransport>d__47.MoveNext() 

        in System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
        in System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
        in System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
        in Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.<SelectAndStartTransport>d__44.MoveNext() 

        in Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.<SelectAndStartTransport>d__44.MoveNext() 

        in System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
        in System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
        in Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.<StartAsyncCore>d__41.MoveNext() 

        in System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
        in System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
        in Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.<StartAsync>d__40.MoveNext() 

        in System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
        in System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
        in Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionFactory.<ConnectAsync>d__3.MoveNext() 

        in Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionFactory.<ConnectAsync>d__3.MoveNext() 

        in System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
        in System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
        in Microsoft.AspNetCore.SignalR.Client.HubConnection.<StartAsyncCore>d__58.MoveNext() 

        in System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
        in System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
        in Microsoft.AspNetCore.SignalR.Client.HubConnection.<StartAsyncInner>d__50.MoveNext() 

        in System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
        in System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
        in Microsoft.AspNetCore.SignalR.Client.HubConnection.<StartAsync>d__49.MoveNext() 

        in System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
        in System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
        in System.Runtime.CompilerServices.TaskAwaiter.GetResult()
        in WPF.MainWindow.<<-ctor>b__4_4>d.MoveNext() in repository/MainWindow.xaml.cs:line 90 

 (#0) Microsoft.AspNetCore.Http.Connections.Client.TransportFailedException: WebSockets failed: The 'User-Agent' header must be modified using the appropriate property or method Parameter name: name
 ---> System.ArgumentException: The 'User-Agent' header must be modified using the appropriate property or method Parameter name: name
    in System.Net.WebHeaderCollection.ThrowOnRestrictedHeader(String headerName)
    in System.Net.WebHeaderCollection.Set(String name, String value)
    in Microsoft.AspNetCore.Http.Connections.Client.Internal.WebSocketsTransport..ctor(HttpConnectionOptions httpConnectionOptions, ILoggerFactory loggerFactory, Func`1 accessTokenProvider)
    in Microsoft.AspNetCore.Http.Connections.Client.Internal.DefaultTransportFactory.CreateTransport(HttpTransportType availableServerTransports)
    in Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.<StartTransport>d__47.MoveNext() 

    in System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
    in System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    in System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
    in Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.<SelectAndStartTransport>d__44.MoveNext() 

  (#1) Microsoft.AspNetCore.Http.Connections.Client.TransportFailedException: ServerSentEvents failed: The transport is disabled by the client.<--- 

 (#2) Microsoft.AspNetCore.Http.Connections.Client.TransportFailedException: LongPolling failed: The transport is disabled by the client.
 <---

代码:

        HubConnection Connection = new HubConnectionBuilder().WithUrl($"..", options => {
        options.UseDefaultCredentials = true; 
        options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets;
        options.Headers["user-agent"] = "Mozilla/5.0";
    }).Build();


Task.Run(async () =>
            {
                try
                {
                    await Connection.StartAsync(); // exception thrown here
                }
                catch (Exception ex)
                {
                    // handle ex
                }
            });

我看到了 this github issue, this issue and this issue,但我不明白那里附带的解决方案。

我需要添加什么 User-Agent header 以避免此异常?

我相信这应该有效:

using System.Reflection;
using System.Net.WebSockets;
using Microsoft.AspNetCore.Http.Connections;

// 

static void HackWebSocketConfiguration( ClientWebSocketOptions wso )
{
    FieldInfo whcField = typeof(ClientWebSocketOptions).GetField( "requestHeaders", BindingFlags.Instance | BindingFlags.NonPublic );
    WebHeaderCollection whc = (WebHeaderCollection)whcField.GetValue( wso );
    
    MethodInfo awov = typeof(ClientWebSocketOptions).GetMethod( "AddWithoutValidate", BindingFlags.Instance | BindingFlags.NonPublic );
    awov.Invoke( whc, /*headerName:*/ "User-Agent", /*headerValue:*/ "Toaster/1.0" );
}

//

HubConnection Connection = new HubConnectionBuilder()
    .WithUrl( $"..", options =>
    {
        options.UseDefaultCredentials = true; 
        options.Transports = HttpTransportType.WebSockets;
        options.WebSocketConfiguration = ( ClientWebSocketOptions wso ) =>
        {
            HackWebSocketConfiguration( wso );
        };
    })
    .Build();

由于这是一个 .NET Framework 错误,切换到 .NET Core 帮助我解决了这个问题。