6

I am working on a SignalR Clinet-Server connection. My server is WebApi Core 2.1 and my client is WPF .NET Framework 4.7.2.

On the client side I have a singleton hub service with one Instance to recive messages from server:

using System.Collections.ObjectModel;
using Microsoft.AspNetCore.SignalR.Client;

public class HubService
{
    //singleton
    public static HubService Instance { get; } = new HubService();

    public ObservableCollection<string> Notifications { get; set; }

    public async void Initialize()
    {
        this.Notifications = new ObservableCollection<string>();

        var hubConnection = new HubConnectionBuilder()
            .WithUrl(UrlBuilder.BuildEndpoint("Notifications"))
            .Build();

        hubConnection.On<string>("ReciveServerUpdate", update =>
        {
            //todo
        });

        await hubConnection.StartAsync();
    }
}

i initialize it as singleton:

    public MainWindowViewModel()
    {
        HubService.Instance.Initialize();
    }

While I'm debugging, on MainWindowViewModel im hitting that HubService.

On Server side its look like this.

Hub:

using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;

public class NotificationsHub : Hub
{
    public async Task GetUpdateForServer(string call)
    {
        await this.Clients.Caller.SendAsync("ReciveServerUpdate", call);
    }
}

Im trigering send message in this way in my controller's methods:

    [HttpPost]
    public async Task<IActionResult> PostTask([FromBody] Task task)
    {
        if (!this.ModelState.IsValid)
        {
            return this.BadRequest(this.ModelState);
        }

        this.taskService.Add(task);

        //here im calling sending message. When im debugging
        //i see one connection from my WPF with unique ConnectionId
        await this.notificationsHub.Clients.All.SendAsync("ReciveServerUpdate", "New Task in database!");

        return this.Ok(task);
    }

As I wrote before, while I'm debugging my WebApi, in Clients I have exactly one connection from my WPF. When I turn off WPF, connection count = 0 so connections works perfectly.

But when I call SendAsync(), I'm not reciving any information in WPF in hubConnection.On. Funny thing, yesterday it works perfectly.

So, is my thinking about making HubService as static singleton is right? If its, why i cant recive messages from WebApi by SignalR when my WPF is connected to it?

I asked something similiar yesterday but i found a solution for it. Yesterday, my methods works, i could hit hubConnection.On when i get any message from WebApi. My question from yestarday.

EDIT

Injection of HUb to controller:

    private readonly ITaskService taskService;

    private readonly IHubContext<NotificationsHub> notificationsHub;

    public TaskController(ITaskService taskService, IHubContext<NotificationsHub> notificationsHub)
    {
        this.taskService = taskService;
        this.notificationsHub = notificationsHub;
    }

And Startup.cs only SignalR things (i deleted other things not related to signal):

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpContextAccessor();
        services.AddSignalR();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseSignalR(routes => routes.MapHub<NotificationsHub>("/Notifications"));
    }

EDIT2

Here is connection that i can get it, when my client WPF will register his connection:

enter image description here

michasaucer
  • 4,562
  • 9
  • 40
  • 91
  • 1
    Show the code how have you injected the `NotificationsHub` in your controller. – TanvirArjel May 29 '19 at 12:24
  • @TanvirArjel i added `Startup.cs` too (only with signalR). Look into my edit – michasaucer May 29 '19 at 12:28
  • What i know, when i have something like `static Instance` with `{ get; } = New` it should work like singleton, in this case i wanted to achive always-on `Hub` to recive messages from `Webapi` when someone call `Post` action – michasaucer May 29 '19 at 12:32
  • 1
    I tried your code with all kinds of clients (wpf/console/even with a browser), it always works fine for me.The `hubConnection.On("ReciveServerUpdate", update => {//todo});` always be invoked when I send a request to `PostTask`. Is there a minimal demo that reproduces? – itminus May 30 '19 at 08:32
  • 1
    Beacuse... it works! I just didnt know that while im debugging i cant acces into `hub.On` method... So, i need to close this question or just leave it to te next generations? You are right @itminus. I just lost a lot of time trying to debug it – michasaucer May 30 '19 at 08:38
  • :) That's really a question of Schrodinger .... I believe if you cannot reproduce the same issue, it's better to update your question to remind someone who wants to investigate. But don't remove this question in case that's a bug that we haven't realized for the present. – itminus May 30 '19 at 08:44
  • I belive, you can post an answer. I will mark it, because it helps tbh – michasaucer May 30 '19 at 08:49
  • Could you tell me, your instance of VS debugger get into `hubConnnection.On`? Becuase i pupulated `Notifications` with `updates` from that method, and debugger when i posted a task didnt trigger my breakpoint, but `Notifications` list was populated – michasaucer May 30 '19 at 08:51
  • @michasaucer Yes. The breakpoint is triggered both in VS & VSCode – itminus May 30 '19 at 08:55
  • @michasaucer When you say "didnt trigger my breakpoint", how do you configure the arguments of handler ? The number of arguments must be the same. – itminus May 30 '19 at 08:59
  • I just set up breakpoint in `hubConnection.On` and it never trigger. When i just cheking, what is in `Notifications`, there was messages from `Webapi` sent by hub – michasaucer May 30 '19 at 09:19
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/194159/discussion-between-itminus-and-michasaucer). – itminus May 30 '19 at 09:21
  • @michasaucer Have you restarted the client when you debug? – itminus May 30 '19 at 09:30
  • @itminus thanks for invest your time. Please, post answer so i will mark it as resolve for my problem – michasaucer May 30 '19 at 15:25

1 Answers1

4

I tried your code with all kinds of clients (wpf/console/even with a browser), it always works fine for me. The hubConnection.On<string>("ReciveServerUpdate", update => {//todo}); always be invoked when I send a request to PostTask.

I'm not sure why (sometimes) it doesn't work for you somehow . However, when SignalR client has connected to server but gets no message from server, there're possible two reasons:

  1. Your PostTask([FromBody] Task task) action method is not executed. Let's say this is an ApiController method, if the browser posts a request with a Content-Type of application/www-x-form-urlencoded by accident, the invocation of Clients.All.SendAsync(..., ...); won't be executed at all.
  2. The handler of SigalR client (hubConnection.On<>(method,handler)) must has exactly the same argument list as the invocation in order to receive messages. We must be very careful when dealing with this.

  3. Finally, it's better to add a reference to Microsoft.Extensions.Logging.Console

    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.*" />
    

    so that we could enable logging to troubleshoot :

    var hubConnection = new HubConnectionBuilder()
        .WithUrl(UrlBuilder.BuildEndpoint("Notifications"))
        .ConfigureLogging(logging =>{
            logging.AddConsole();        // enable logging
        })
        .Build();
    
itminus
  • 23,772
  • 2
  • 53
  • 88
  • Please, mention that my code works in your answer for the next generation of .NET developers (some of them diving straight into answers) – michasaucer May 31 '19 at 07:12