简体   繁体   中英

How to work with SignalR in asp.net core 3.0

Hy, We're working on an asp.net core project that depends on Signal R. lastly we updated our project from asp.net core 2.2 to 3.0 and the Signal R stopped working. In the documentation we configured everything (I think correctly) but is still doesn't work. What did we miss?

Asp.net Core 3.0 API

public class Startup
{
     private readonly string corsPolicy = "CorsPolicy";
     private static string[] AllowdOrigins() => return new string[] {"localhost:4200","example.com"};

     public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            ConfigureAuthentication(services);


            ///MICROSOFT SQL DATABASE
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection")
            ));

            services.Configure<ApiBehaviorOptions>(options =>
            {
                options.SuppressModelStateInvalidFilter = true;
            });

            services.Configure<ForwardedHeadersOptions>(options =>
            {
                options.KnownProxies.Add(IPAddress.Parse("XX.XX.XX.XX"));
            });

            services.AddSignalR();
            services.AddControllers();

            //services dependencies

        }


        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseHttpsRedirection();
            app.UseRouting();
            app.UseCors(corsPolicy);

            //app.UseForwardedHeaders(new ForwardedHeadersOptions
            //{
            //    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
            //});

            app.UseAuthentication();
            app.UseAuthorization();


            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapHub<ChatHub>("/chat");
            });



            DummyData.Initialize(app);
        }
        private void ConfigureAuthentication(IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddPolicy(corsPolicy,
                builder =>
                {
                    builder
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowAnyOrigin()
                    .AllowCredentials()
                    .WithOrigins(AllowdOrigins());
                });
            });

            services.AddHttpContextAccessor();



            // configure strongly typed settings objects
            var appSettingsSection = Configuration.GetSection("AppSettings");
            services.Configure<AppSettings>(appSettingsSection);

            // configure jwt authentication
            var appSettings = appSettingsSection.Get<AppSettings>();
            var key = Encoding.ASCII.GetBytes(appSettings.Secret);

            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false
                };
            });
        }
}

[EnableCors("CorsPolicy")]
    public class ChatHub : Hub
    {
        private static Dictionary<string, int> onlineClientCounts = new Dictionary<string, int>();
        private static readonly string FrontPrefix = "_FRONT";

        public ChatHub()
        {
        }

        [HubMethodName("ConnectFrontend")]
        public async Task ConnectFrontend(int sessionId)
        {

            //////
        }

        [HubMethodName("ConnectDevice")]
        public async Task ConnectDevice(int sessionId)
        {
            //// This method should be called but it isn't.
        }

        public void DisConnect(int sessionId, int userId)
        {
           //////////
        }

        [HubMethodName("SendJsonToFrontends")]
        public async Task SendJsonToFrontends(int sessionId, string jsonString)
        {
///
        }

        [HubMethodName("SendJsonToAll")]
        public async Task SendJsonToAll(int sessionId, string jsonString)
        {
////
        }
    }

Angular project

export class SignalRService {

  private connection: signalR.HubConnection;

  public newMessage = new Subject<SocketMessage>();

  constructor() {

  }

  public connectFront() {

    this.connection = new signalR.HubConnectionBuilder()
        .withUrl("http://localhost:2525/chat")//(environment.baseSignalR)
        .configureLogging(signalR.LogLevel.Trace)
        .build();


    this.connection.on("ReceiveJson", data => { this.handleJsonMessage(data) });

    //handles the first connection message
    this.connection.start().then(() => this.sendConnectionMessage());

    //handles the incomming messages
    this.connection.on("ReceiveJson", data => this.handleJsonMessage(data));
    this.connection.on("ReceiveJsonFrontend", data => this.handleJsonMessage(data));
  }

  private sendConnectionMessage() {
    var sessionId = sessionStorage.getItem("SessionId");
    if (sessionId != null) {
        this.connection.invoke("ConnectFrontend", sessionId).catch((error) => { debugger; console.log(error); });
    }
  }

  public sendWebsocketMessageToAll(msg: SocketMessage) {
    var sessionId = sessionStorage.getItem("SessionId");
    if (sessionId != null) {
      this.connection.invoke("SendJsonToAll", sessionId, JSON.stringify(msg)).catch((error) => console.log(error));
    }
  }

  public sendWebsocketMessageToFrontend(msg: SocketMessage) {
    var sessionId = sessionStorage.getItem("SessionId");
    if (sessionId != null) {
      this.connection.invoke("SendJsonToFrontends", sessionId, JSON.stringify(msg)).catch((error) => console.log(error));
    }
  }

  private handleJsonMessage(data: string) {
    this.newMessage.next(this.getSocketMessage(data));
  }

  public getSocketMessage(data: string): SocketMessage {
    var msg: SocketMessage = JSON.parse(data);
    return msg;
  }

  public disconnect() {
    this.connection.stop();
  }
}

angular output: 在此处输入图像描述

Api output: 在此处输入图像描述

Just create an web app API with angular template you can view my code for your ref

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
        services.AddSpaStaticFiles(configuration =>
        {
            configuration.RootPath = "ClientApp/dist";
        });
        services.AddSignalR().AddJsonProtocol(options =>
        {
            options.PayloadSerializerOptions.WriteIndented = false;
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
        }

        app.UseStaticFiles();
        if (!env.IsDevelopment())
        {
            app.UseSpaStaticFiles();
        }

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller}/{action=Index}/{id?}");
            endpoints.MapHub<ChatHub>("/chatHub");
        });

        app.UseSpa(spa =>
        {
            spa.Options.SourcePath = "ClientApp";

            if (env.IsDevelopment())
            {
                spa.UseAngularCliServer(npmScript: "start");
            }
        });
    }

In FE side. Note: use new package @microsoft/signalr

import * as signalR from "@microsoft/signalr";
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
    title = 'app';

    ngOnInit() {
        const connection = new signalR.HubConnectionBuilder()
            .withUrl("/chathub")
            .build();

        connection.on("receiveMessage", (username: string, message: string) => {
            console.log(username);
            console.log(message);
        });

        connection.start().then(() => {
            connection.send("sendMessage", "aaa", "aaaa")
                .then(() => console.log("done"));

        }).catch(err => document.write(err));
    }
}

Well I finaly figured it out with the help of Tony,

Apperently It went wrong in the methods of the SignalR chat hub. The methods allowed only integers as parameters but it needed to be strings. I don't know it it has to do with some other settings but my guess now is that signalr cant convert the request parameters to something other then strings.

When I changed it to strings it worked.

It seems, that you have configured JWT based authentication on the server side and do not provide a token for SignalR connection. Try to provide a token using the accessTokenFactory:

this.hubConnection = new signalR.HubConnectionBuilder()
            .withUrl(`${environment.urlAddress}/chathub`, {
                accessTokenFactory: () => this.token
            })
            .build()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM