SignalR AspNetCore 无法连接到远程服务器 ---> System.Net.WebException
SignalR AspNetCore Unable to connect to the remote server ---> System.Net.WebException
我在从我的 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 hub 运行 在无状态服务结构服务中,部署在 azure 服务结构集群上。
At the server side I am using nuget library
Microsoft.AspNetCore.SignalR
Below given is the AspNetCore 2.0
Stateless service side code for the reference-
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 服务架构集群上 运行 连接时,我不确定为什么在将 SignalR 客户端与 SignalR 集线器连接时遇到问题。
For the additional information I have checked network and
load-balancer rules and there is no connectivity issue from the
network side. (I have verified it by adding a controller in this
service and I am able to retrieve results from the controller).
我做了一些研发,发现问题可能与负载平衡器亲和力有关。为了验证负载平衡器亲和性问题,我已经使用 HTTP 协议部署了应用程序,并且我能够在多次重试连接尝试中连接到它。这提示我 Load Balancer Affinity 可能会导致此问题。
此外,我检查了应用程序端口的负载均衡器规则,发现负载分配设置为 none。按照我的理解应该是"SourceIPProtocol"。
目前该服务部署在一个 5 节点服务结构集群中,当我将服务缩减到 1 个节点时,我能够在第一次尝试中使用 .net 框架应用程序通过 HTTP 和 HTTPS 协议连接到该服务。
使用自签名证书部署服务。
这里剩下的唯一问题是我无法通过 HTTPS 协议从 .net 标准应用程序连接服务并收到错误消息-
The certificate authority is invalid or incorrect
为了从 .net 框架应用程序连接,我在信号器连接代码之前的给定行下面写了-
ServicePointManager.ServerCertificateValidationCallback += (o, c, ch, er) => true;
以上给出的代码在 .net 标准应用程序中不起作用。
通过进一步的研发,我发现在 .NET Core 中,ServicePointManager
被替换为 HttpClientHandler
实例本身的配置。您需要在 IHubConnectionBuilder 实例上调用 .WithMessageHandler
并提供一个设置了 ServerCertificateCustomValidationCallback
的 HttpClientHandler 实例。
当我使用下面给定的代码时,我无法通过 HTTPS 协议连接到 SignalR hub-
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 集线器。
我在从我的 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 hub 运行 在无状态服务结构服务中,部署在 azure 服务结构集群上。
At the server side I am using nuget library
Microsoft.AspNetCore.SignalR
Below given is the AspNetCore 2.0 Stateless service side code for the reference-
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 服务架构集群上 运行 连接时,我不确定为什么在将 SignalR 客户端与 SignalR 集线器连接时遇到问题。
For the additional information I have checked network and load-balancer rules and there is no connectivity issue from the network side. (I have verified it by adding a controller in this service and I am able to retrieve results from the controller).
我做了一些研发,发现问题可能与负载平衡器亲和力有关。为了验证负载平衡器亲和性问题,我已经使用 HTTP 协议部署了应用程序,并且我能够在多次重试连接尝试中连接到它。这提示我 Load Balancer Affinity 可能会导致此问题。 此外,我检查了应用程序端口的负载均衡器规则,发现负载分配设置为 none。按照我的理解应该是"SourceIPProtocol"。 目前该服务部署在一个 5 节点服务结构集群中,当我将服务缩减到 1 个节点时,我能够在第一次尝试中使用 .net 框架应用程序通过 HTTP 和 HTTPS 协议连接到该服务。
使用自签名证书部署服务。
这里剩下的唯一问题是我无法通过 HTTPS 协议从 .net 标准应用程序连接服务并收到错误消息-
The certificate authority is invalid or incorrect
为了从 .net 框架应用程序连接,我在信号器连接代码之前的给定行下面写了-
ServicePointManager.ServerCertificateValidationCallback += (o, c, ch, er) => true;
以上给出的代码在 .net 标准应用程序中不起作用。
通过进一步的研发,我发现在 .NET Core 中,ServicePointManager
被替换为 HttpClientHandler
实例本身的配置。您需要在 IHubConnectionBuilder 实例上调用 .WithMessageHandler
并提供一个设置了 ServerCertificateCustomValidationCallback
的 HttpClientHandler 实例。
当我使用下面给定的代码时,我无法通过 HTTPS 协议连接到 SignalR hub-
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 集线器。