【问题标题】:SignalR AspNetCore Unable to connect to the remote server ---> System.Net.WebExceptionSignalR AspNetCore 无法连接到远程服务器---> System.Net.WebException
【发布时间】:2018-07-11 15:01:40
【问题描述】:

我在从我的 SignalR 客户端应用程序连接到 SignalRHub 时遇到问题,下面给出的是错误日志-

info: Microsoft.AspNetCore.Sockets.Client.WebSocketsTransport[0]
      02/01/2018 15:20:13: Connection Id f763a939-3fb9-4812-ae6e-dfe3198ab37b: Starting transport. Transfer mode: Text.
fail: Microsoft.AspNetCore.Sockets.Client.HttpConnection[9]02/01/2018 15:20:13: Connection Id f763a939-3fb9-4812-ae6e-dfe3198ab37b: Failed to start connection. Error starting transport 'WebSocketsTransport'.
System.Net.WebSockets.WebSocketException (0x80004005): Unable to connect to the remote server ---> System.Net.WebException: The remote server returned an error: (404) Not Found.
   at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Net.WebSockets.ClientWebSocket.<ConnectAsyncCore>d__21.MoveNext()
   at System.Net.WebSockets.ClientWebSocket.<ConnectAsyncCore>d__21.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Sockets.Client.WebSocketsTransport.<Connect>d__19.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Sockets.Client.WebSocketsTransport.<StartAsync>d__16.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Sockets.Client.HttpConnection.<StartTransport>d__46.MoveNext()

SignalR 集线器在无状态服务结构服务中运行,并部署在 azure 服务结构集群上。

在服务器端,我使用的是 nuget 库 Microsoft.AspNetCore.SignalR 下面给出的是 AspNetCore 2.0 无状态服务端代码供参考-

Startup.cs:-

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace SampleChat
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddSignalR();
            services.AddCors(options =>
            {
                options.AddPolicy("CorsPolicy",
                    builder => builder.AllowAnyOrigin()
                        .AllowAnyMethod()
                        .AllowAnyHeader()
                        .AllowCredentials());
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
                app.UseDeveloperExceptionPage();

            app.UseMvc();

            app.UseFileServer();

            app.UseCors("CorsPolicy");

            app.UseWebSockets();

            app.UseSignalR(routes => { routes.MapHub<ChatHub>("SignalRHub"); });
        }
    }
}

ChatHub.cs:-

using Microsoft.AspNetCore.SignalR;

namespace SampleChat
{
    public class ChatHub : Hub
    {
        public void Send(string message)
        {
            // Call the broadcastMessage method to update clients.
            Clients.All.InvokeAsync("Send", message);
        }
    }
}

SampleChat.cs

using System.Collections.Generic;
using System.Fabric;
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.ServiceFabric.Services.Communication.AspNetCore;
using Microsoft.ServiceFabric.Services.Communication.Runtime;
using Microsoft.ServiceFabric.Services.Runtime;

namespace SampleChat
{
    /// <summary>
    ///     The FabricRuntime creates an instance of this class for each service type instance.
    /// </summary>
    internal sealed class SampleChat : StatelessService
    {
        public SampleChat(StatelessServiceContext context)
            : base(context)
        {
        }

        /// <summary>
        ///     Optional override to create listeners (like tcp, http) for this service instance.
        /// </summary>
        /// <returns>The collection of listeners.</returns>
        protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
        {
            return new[]
            {
                new ServiceInstanceListener(serviceContext =>
                    new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
                    {
                        ServiceEventSource.Current.ServiceMessage(serviceContext, $"Starting Kestrel on {url}");

                        return new WebHostBuilder()
                            .UseKestrel()
                            .ConfigureServices(
                                services => services
                                    .AddSingleton(serviceContext))
                            .UseContentRoot(Directory.GetCurrentDirectory())
                            .UseStartup<Startup>()
                            .UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
                            .UseUrls(url)
                            .Build();
                    }))
            };
        }
    }
}

在客户端,我正在使用 nuget 库 Microsoft.AspNetCore.SignalR.Client 下面给出的是 SignalR 客户端代码-

Program.cs:-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleChatCoreApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                SignalRConnector.ConnectoToSignalR().GetAwaiter().GetResult();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            };
            Console.ReadKey();
        }
    }
}

SignalRConnector.cs:-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR.Client;

namespace SampleChatCoreApplication
{
    static class SignalRConnector
    {
        public static async Task<bool> ConnectoToSignalR()
        {
            var connection = new HubConnectionBuilder()
                .WithUrl("http://localhost:8634/SignalRHub")
                .WithConsoleLogger()
                .WithTransport(Microsoft.AspNetCore.Sockets.TransportType.WebSockets)
                .Build();
            connection.On<string>("Send", data =>
            {
                Console.WriteLine($"Received data: {data}");
            });

            await connection.StartAsync();

            await connection.InvokeAsync("Send", "Send data to Hub");

            Console.ReadKey();

            return true;
        }
    }
}

当我在本地系统中运行无状态服务时,我能够成功连接 SignalR Hub。

当服务在 Azure Service Fabric 集群上运行时,我不确定为什么在将 SignalR 客户端与 SignalR 集线器连接时遇到问题。

有关其他信息,我已检查过网络和 负载均衡器规则,并且没有来自 网络端。 (我已经通过在此添加控制器来验证它 服务,我可以从控制器中检索结果)。

【问题讨论】:

  • 您确定 localhost:8634/SignalRHub 是 SignalR 服务器代码的正确 URL。该错误在该位置显示为 404。
  • 出于安全原因,我无法提供用于运行此应用程序的实际 URL。正如我在问题摘要中提到的,使用正确的 URL 我能够与使用相同 URL 托管的 MVC 控制器进行通信。所以这个问题似乎与 AspNetCore SignalR 库本身有关。
  • 您是否尝试导航到 YOURHUBURL/signalr/negotiate?如果集线器已正确初始化并启动,它应该以 json 文件回答

标签: websocket signalr azure-service-fabric stateless asp.net-core-mvc-2.0


【解决方案1】:

我做了一些研发,发现这个问题可能与负载均衡器的关联性有关。为了验证负载均衡器关联性问题,我使用 HTTP 协议部署了应用程序,并且能够在多次重试连接尝试中与其连接。这给了我一个提示,负载均衡器关联性可能会导致这里出现问题。 此外,我检查了应用程序端口的负载均衡器规则,发现负载分配设置为无。据我了解,它应该是“SourceIPProtocol”。 目前该服务部署在一个 5 节点服务结构集群中,当我将服务缩减到 1 个节点时,我能够使用 .net 框架应用程序通过 HTTP 和 HTTPS 协议第一次尝试连接该服务。

使用自签名证书部署服务。

这里剩下的唯一问题是我无法通过 HTTPS 协议从 .net 标准应用程序连接服务并收到错误 - The certificate authority is invalid or incorrect

为了从 .net 框架应用程序连接,我在信号器连接代码之前的给定行下方编写 - ServicePointManager.ServerCertificateValidationCallback += (o, c, ch, er) =&gt; true;

上述代码在 .net 标准应用程序中不起作用。

通过进一步的研发,我发现在 .NET Core 中,ServicePointManager 被替换为 HttpClientHandler 实例本身的配置。您需要在 IHubConnectionBuilder 实例上调用 .WithMessageHandler 并提供一个带有 ServerCertificateCustomValidationCallback 集的 HttpClientHandler 实例。

当我使用以下给定代码时,我无法通过 HTTPS 协议连接 SignalR 集线器-

var handler = new HttpClientHandler
                        {
                            ClientCertificateOptions = ClientCertificateOption.Manual,
                            ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => { return true; }
                        };

                        Connection = new HubConnectionBuilder()
                            .WithUrl(url)
                            .WithTransport(Microsoft.AspNetCore.Sockets.TransportType.WebSockets)
                            .WithMessageHandler(handler)
                            .Build();

当我将传输更改为 TransportType.ServerSentEvents 或 TransportType.LongPolling 时,我能够毫无问题地连接到 SignalR 集线器。

【讨论】:

  • 在进一步的说明中,我发现-“对于 WebSockets,在 Alpha2 中,它不支持客户端证书身份验证。但是,在每晚的 Preview1 构建中,我们可以使用 HubConnectionBuilder 上的 .WithWebSocketOptions API 来配置ClientWebSocketOptions 对象,其中也有客户端证书配置。”
猜你喜欢
  • 2021-05-08
  • 2015-05-27
  • 2018-03-20
  • 1970-01-01
  • 2016-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多