. Netcore SignalR tread on the pit

Source: Internet
Author: User


Background


Due to the recent company to do small program chat, so.NetFramworkversion versionSignalRof the can not be used. Because there are nowindowsobjects in the applet,JQueryit cannot be used. AndSignalrThe JS client is dependentJQuery.



So look at the core version of theSignarlRtest, found that can be run in, but the JS client to change towebscoekttheir own. If you need to change the version, you can comment downstairs.


Objective


The main purpose of this article is to introduce.NetCoresome of the pits used in the releaseSignalR, and to provide a solution. Most of the previous articles were simply an introduction to the official demo. Not really put into use, some of these small problems are not digging deep and processing.


Cross-domain issues


. Net frmaworkversion is simple, reference the corresponding package, just addaddcores ()on the line, and the core version of the control more accurate. The followingconfigureservicesadds the following code


services.AddCors(options => options.AddPolicy("SignalR",
    Builder =>
    {
        builder.AllowAnyMethod() //Allow any request mode
               .AllowAnyHeader() //Allow any header
               .AllowAnyOrigin() //Allow any origin
               .AllowCredentials();//Allow verification
             //.WithOrigins(domins) //Specify a specific domain name to access
    }));


ThenConfigureuse the defined cross-domain policy


App. Usecors ("SignalR");
Using Redis scale Out


and.Net Framworkthe same,. The Netcore versionSignalRcan use Redis to communicate between multiple servers. However, if the Redis is not connected successfully, the program will not error, but the communication will not work properly. and.Net FramworkSignalRThe version of the words, the address directly 404.



So I want to monitor if Redis is connected successfully at boot time. ButSignalRthe official documentation is simple to use, evenRedishow to configure it. So you can only go to the biggest dating site to find. A turn to see issue, finally found how to monitor.



Poke me at the details



To configure it with the following code, you can monitorRedisif the connection is successful.


services.AddSignalR()
        .AddMessagePackProtocol()
        .AddRedis(o => {
            o.ConnectionFactory = async writer => { var config = new ConfigurationOptions
                {
                    AbortOnConnectFail = false };
                config.EndPoints.Add(IPAddress.Loopback, 0);
                config.SetDefaultPorts(); var connection = await ConnectionMultiplexer.ConnectAsync(config, writer);
                connection.ConnectionFailed += (_, e) => {
                    Console.WriteLine("Connection Redis failed.");
                }; if (!connection.IsConnected)
                {
                    Console.WriteLine("Connection did not connect.");
                } return connection;
            };
        });

But found in this way,Redisconnected 2 times, according to reason should not amount. Plus I have a lot of things to study source code. So just ask the author directly in this issue. We haven't found the reason yet. See the link above for details.


WebSocket Load Balancing Configuration


Using load balancing to forward requests requires a special configuration for WebSocket requests.



Find the operation of the classmate configuration, after the configuration to tell me that this link can only make a GET request, cannot make a POST request. Manual Black question mark ...



Such words can only be used inWebSocketa way, likeLongPollinand the agreement canSSEnot be used.



I'm going to, like, a hole? So let ops to send me the configuration code, as follows


proxy_http_version 1.1;
proxy_set_header  Host $host;
proxy_set_header   Upgrade $http_upgrade;
proxy_set_header   Connection "upgrade";
proxy_connect_timeout 300;
proxy_read_timeout 300;
proxy_send_timeout 300;


So I publish the app to a local virtual machine and run it in adockerway. Then write the configuration into the Nginx configuration file.



The discovery really does not make a POST request and returns400.400the idea of a think request exception. There must be a problem with this configuration. So go to dating site to find issue, and sure enough to let me find. In a issue, the configuration provided is as follows


proxy_http_version   1.1;
proxy_set_header   Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;


The difference isproxy_set_header Connection, did not write dead, so I changed the configuration, and really good.



proxy_set_header Connectioncan not write dead, to get from the request header. There is no problem with other requests.


ConnectionID get


In theJSclient code, no more ConnectionID are provided. That is, if you want to use, you need to change the source Add. It's no problem, but Microsoft's big God shouldn't make such a low-level mistake.ConnectionIdwhen thenegotiaterequest is clear, why not open it? Is it a bug? There shouldn't be such a low-level bug.



So went to see issues, sure enough, there are also people asked, the author also has an explanation.



Go to dating sites and see



The general meaning is the use of theConnectonIdserver side, the client should not use this uncontrolled way to communicate. can be usedGrouporUserthis controllable way of communication, and there are examples given.


Here, in the use of the.Net Framworkversion, our site is usedConnectionIdto communicate, often the re-connection causedConnectionIdby the change, and thus communication failure.


So I also adjusted the next design ideas, useGroupto communicate.



All of the above has been done, hard so long, according to reason should be no problem! Then release online!


The big Pit is here.


Apply my local test everything is OK, the test machine is not a problem, and then sent to the production environment, the results of the problem arises.



Because both local and test environments are single servers, testing is fine. and to the production environment, the server has more than one. No matter how I js set, always after thenegotiaterequest is executed, the next connection request must be 404, and returnNo Connection with that Id.



Such as









See this error, the first reaction, my idea isRedisnot connected to success, so only a single run? So I was on top of the Redis code with a variety of monitoring, found that the connection was successful. Code review N-Times code, there is no place to change.



So the official documents went through. Finally found that JS can be configured in the following


let connection = new signalR.HubConnectionBuilder()
    .withUrl("/myhub", {
        skipNegotiation: true,
        transport: signalR.HttpTransportType.WebSockets
    });
    .build();


The above code means skipping thenegotiatehandshake and usingWebSocketthe connection directly.



According to the document configuration, I go, really can. A communication connection was established because only one request was sent.



I am not calm now, can only deploy a server? How is stability guaranteed? This is still used in the small program (JS client has been modified), the low version can not be used websocket, is the lower version of it? How does the flow of the machine resist the live? Do you want to change your plan to make a communication?



No way, only big strokes. The source clone down, took a little time to read the next, find the following code


private async Task<HttpConnectionContext> GetConnectionAsync(HttpContext context)
{ var connectionId = GetConnectionId(context); if (StringValues.IsNullOrEmpty(connectionId))
    { // There‘s no connection ID: bad request context.Response.StatusCode = StatusCodes.Status400BadRequest;
        context.Response.ContentType = "text/plain";
        await context.Response.WriteAsync("Connection ID required"); return null;
    } if (!_manager.TryGetConnection(connectionId, out var connection))
    { // No connection with that ID: Not Found context.Response.StatusCode = StatusCodes.Status404NotFound;
        context.Response.ContentType = "text/plain";
        await context.Response.WriteAsync("No Connection with that ID"); return null;
    } return connection;
}

What does this piece of code mean? If connection didn't find it locally, it would return 404!



I go, is it a code bug?



Add some extra.


In the.Net Framworkversion, the source code will beConnectionIdverified. Validation passes, but if connection is not found locally, a new connection is created to enable communication between multiple servers. So I have the above question. However, the disadvantage is that it is impossible to monitor when the client disconnects.


So I mentioned a issue and asked the author. poke me at the details



The reply Received is


It ' s not a bug it's by design. The ASP . NET Core SignalR requires sticky sessions when the using scale is out. This means your need to pin a connection to a particular serve


What do you mean? This is not a bug, that's how it's designed.SignalRwhen used, the session is persisted and the request falls to the same server. This is more stable and can also monitor the client situation in real time.



So find the operation of the students in the load configured under the next session to keep, test again, finally can.


Summarize


In the process of this useSignalR, encountered too many pits. It took a few hours to sort it out and record it and share it with you. Hope to help those who are prepared or have plans to use. Net core. Neter


Cgyqu

Source: https://www.cnblogs.com/cgyqu/p/9563193.html

This site uses the "Signature 4.0 International" Creative sharing agreement, reproduced in the article obvious location of the author and source.


. Netcore SignalR tread on the pit


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.