1
votes

I'm new to SignalR (the Core version, currently 1.0.0-alpha2-final). I have a view rendered from a controller action, and the page interacts with a few APIs without reloading. I would like to update parts of the page from other (API style) controller methods that do not return anything themselves. So the index view renders a page with controls, and also connects to SignalR.

What I have is

<div id="DisplayMessages"></div>

as a placeholder for messages.

My controller has a dependency injection of IHubContext.

let connection = new signalR.HubConnection("/signalr", { transport: signalR.TransportType.LongPolling });

connection.on('send',
    data => {
        var DisplayMessagesDiv = document.getElementById("DisplayMessages");
        DisplayMessagesDiv.innerHTML += "<br/>" + data;
    });
connection.onClosed = e => {
    console.log('connection closed');
};    
connection.start().then(() => connection.invoke('send', 'Hello'));

function SendMessage() {
    var msg = document.getElementById("txtMessage").value;
    connection.invoke('send', msg);
}

I can send messages to all clients from inside my controller method like

    public JsonResult DoSomething([FromBody] DoSomethingParameters parameters)
        doSomething();
        _signalRHub.Clients.All.InvokeAsync("Send", "Did something with " + parameters.SomeParameter);

What I cannot figure out how to only send it to the client that initially rendered the page that now sends to the API. There is an example in the sample that maps to the User's identity, but that is useless since the page can be rendered by an anonymous user. How could I receive the connection ID of the client that is requesting the API whilst at the same time his browser is connected to SignalR?

Thanks for any info!

1
After thinking this through again, it is probably not possible. I have now helped myself by creating a group with the name of the user; groups are available from IHubContext. - ExternalUse
You can also pass arbitrary values in the query string you use to start the connection. You could use this to provide a unique user identifier that you could then use on the server to identify clients you want to send updates to. - Pawel
Hi Pawel, the problem is that I do not have control over some of the components generating API calls, so I cannot necessarily identify the component's call to be originating from a page that actually displays the component. Bit difficult to explain I guess. The group method I mentioned does work luckily. - ExternalUse

1 Answers

1
votes

As mentioned in a comment, I think there isn't an answer, since the Hub's Connection ID is only available within the hub and it would require effort to track an anonymous user across the site to use what I'm now doing. As the components require Authorization anyway, I am now creating groups with the Users' name when connecting to the hub.

public override Task OnConnectedAsync()
{
    Groups.AddAsync(Context.ConnectionId, Context.User.Identity.Name);  
    return base.OnConnectedAsync();
}

This allows me to access an injected hubcontext

private readonly IHubContext<SignalRHub> _signalRHub;

public FooController(IHubContext<SignalRHub> signalRHub)
{    
    _signalRHub = signalRHub;
}

and access it from a method:

_signalRHub.Clients.Group(User.Identity.Name).InvokeAsync("Send", User.Identity.Name + ": Message for you");