My understanding is that a new server-side Hub instance is created each time a client calls a hub method (via its hub proxy). But what if I wanted a Hub that would only be used (by server business logic) to send messages to clients, using this syntax:-
Clients.All.Notify(data);
I would be using a .Net client by the way, which would receive such messages using this sort of syntax:-
_myHubProxy.On<SomeData>("Notify", data => ...);
If the client never calls any hub methods then would the hub ever be instantiated?
Edit
The article provided by Nikola.Lukovic (see comment below) says:
SignalR creates a new instance of your Hub class each time it needs to handle a Hub operation such as when a client connects, disconnects, or makes a method call to the server.
While I (kind of) understand the need to instantiate a hub each time a method is called, I'm curious as to why it also has to do this when connecting (and disconnecting). I wonder if one of its tasks is to set up the "link" between the Hub and any On<T> event handlers specified on the client's hub proxy?
Related
How to register client on server to listen some change? I want to notify my client and send some data when something changed on my server. Also, I use NetTcpBinding. I tried many examples, but I can't get method from server to register in. I don't have any config file.
Thanks in advance.
There is example of registering client on server.
ChannelFactory<ITrending> factory = new ChannelFactory<ITrending>(
new NetTcpBinding(), new EndpointAddress(#"net.tcp://localhost:6000/ITrending"));
proxy = factory.CreateChannel();
You can use the CallBack functionality in WCF services , it can be used for sending the changes in any entity or object value. In this case, Client must act as a server and server as a Client to receive the updates based on the method in the Client which is receiving the changes.
More detailed explanation : http://www.dotnetcurry.com/wcf/721/push-data-wcf-callback-service
We can create multiple hubs for different things, and to connect to each hub we can create multiple client side hubs with sharing connection so that, one connection being made to all hubs. Now, the problem arises that the hub onconnected method is not raising on each hub server side code.
public class Hub1 : Hub
{
public override Task OnConnected()
{
return base.OnConnected();
}
}
public class Hub2 : Hub
{
public override Task OnConnected()
{
return base.OnConnected();
}
}
let say, on the client side i create the hub1 and hub2 with client side methods defined on both the hubs, then only one of the hubs onConnected method gets called on server side. If I create the hubs on the client side with separate connections then the OnConnected method gets called. So, there any other work around if I want to use the same connection for each hub but also would like to raise the on Connected event of separate hubs.
I tested it by putting debug point on both hubs, and the OnConnected does get invoked on both hubs, as long as you have any subscriptions to both hubs.
See here: Can I debug OnConnected method in SignalR Hub?
Long story short:
By design, if you don't have any subscriptions to the hub, then the javascript client can't get any messages from server so the OnConnected won't get called.
EDIT
See here the Note part:
Note: For JavaScript clients you have to register at least one event
handler before calling the Start method to establish the connection.
See more at the link.
I am building a c#/wpf project.
It's architecture is this:
A console application which will be on a virtual machine (or my home computer) that will be the server side.
A wpf application that will be the client app.
Now my problem is this - I want the server to be able to send changes to the clients. If for example I have a change for client ABC, I want the server to know how to call a service on the clients computer.
The problem is, that I don't know how the server will call the clients.
A small example in case I didn't explain it well:
The server is on computer 1, and there are two clients, on computers 2 and 3.
Client 2 has a Toyota car and client 3 has a BMW car.
The server on computer 1 wants to tell client 2 that it has a new car, an Avenger.
How do I keep track and call services on the clients?
I thought of saving their ip address (from calling ipconfig from the cmd) in the DB - but isn't that based on the WI-FI/network they are connected to?
Thanks for any help!
You could try implementing SignalR. It is a great library that uses web sockets to push data to clients.
Edit:
SignalR can help you solve your problem by allowing you to set up Hubs on your console app (server) that WPF application (clients) can connect to. When the clients start up you will register them with a specified Hub. When something changes on the server, you can push from the server Hub to the client. The client will receive the information from the server and allow you to handle it as you see fit.
Rough mockup of some code:
namepsace Server{}
public class YourHub : Hub {
public void SomeHubMethod(string userName) {
//clientMethodToCall is a method in the WPF application that
//will be called. Client needs to be registered to hub first.
Clients.User(userName).clientMethodToCall("This is a test.");
//One issue you may face is mapping client connections.
//There are a couple different ways/methodologies to do this.
//Just figure what will work best for you.
}
}
}
namespace Client{
public class HubService{
public IHubProxy CreateHubProxy(){
var hubConnection = new HubConnection("http://serverAddress:serverPort/");
IHubProxy yourHubProxy = hubConnection.CreateHubProxy("YourHub");
return yourHubProxy;
}
}
}
Then in your WPF window:
var hubService = new HubService();
var yourHubProxy = hubService.CreateHubProxy();
yourHubProxy.Start().Wait();
yourHubProxy.On("clientMethodToCall", () => DoSometingWithServerData());
You need to create some kind of subscription model for the clients to the server to handle a Publish-Subscribe channel (see http://www.enterpriseintegrationpatterns.com/patterns/messaging/PublishSubscribeChannel.html). The basic architecture is this:
Client sends a request to the messaging channel to register itself as a subscriber to a certain kind of message/event/etc.
Server sends messages to the channel to be delivered to subscribers to that message.
There are many ways to handle this. You could use some of the Azure services (like Event hub, or Topic) if you don't want to reinvent the wheel here. You could also have your server application track all of these things (updates to IP addresses, updates to subscription interest, making sure that messages don't get sent more than once; taking care of message durability [making sure messages get delivered even if the client is offline when the message gets created]).
In general, whatever solution you choose is plagued with a common problem - clients hide behind firewalls and have dynamic IP addresses. This makes it difficult (I've heard of technologies claiming to overcome this but haven't seen any in action) for a server to push to a client.
In reality, the client talks and the server listens and response. However, you can use this approach to simulate a push by;
1. polling (the client periodically asks for information)
2. long polling (the client asks for information and the server holds onto the request until information arrives or a timeout occurs)
3. sockets (the client requests server connection that is used for bi-directional communication for a period of time).
Knowing those terms, your next choice is to write your own or use a third-party service (azure, amazon, other) to deliver messages for you. I personally like long polling because it is easy to implement. In my application, I have the following setup.
A web API server on Azure with and endpoint that listens for message requests
A simple loop inside the server code that checks the database for new messages every 100ms.
A client that calls the API, handling the response.
As mentioned, there are many ways to do this. In your particular case, one way would be as follows.
Client A calls server API to listen for message
Server holds onto call, waiting for new message entry in database
Client B calls server API to post new message
Server saves message to database
Server instance from step 2 sees new message
Server returns message to Client A.
Also, the message doesn't have to be stored in a database - it just depends on your needs.
Sounds like you want to track users à la https://www.simple-talk.com/dotnet/asp.net/tracking-online-users-with-signalr/ , but in a desktop app in the sense of http://www.codeproject.com/Articles/804770/Implementing-SignalR-in-Desktop-Applications or damienbod.wordpress.com/2013/11/20/signalr-a-complete-wpf-client-using-mvvm/ .
Is there a way to pass client information (such as an Id, username or other contextual information) from the client as part of making a websocket connection from a .net client(console,silverlight etc)?
This is how I'm making the connection to the socket service.
using (WebSocket socket = new WebSocket(#"ws://"+Environment.MachineName+":4502/commandserver"))
{
socket.OnClose += socket_OnClose;
socket.OnData += socket_OnData;
socket.OnOpen += socket_OnOpen;
socket.Open();
}
The ctor has an overload that accepts an "origin" and a "protocol", not sure if this can be used for passing any client information. If not is there an API call I can make to pass in the client information as part of making the connection?
EDIT: I'm using the microsoft library for this and the sample service code adds the service object into a collection in it's ctor to keep track of client sessions. Hence I need a way to pass in some client data to the service object as part of the initial client connection so that I can use this to identify clients and send messages to specific clients (based on an ID for example) from the service.
Hi
Though it's a simple thing, I don't know how to do it.
I'm trying to sign the dll to events happening on the server side.
the clients has an instance of this dll and they have to receive notifications from the server.
on the service I defined (c#):
public delegate ActionResult ActionComplitedHandler(object sender,ActionComplitedEventArgs e);
.
public event ActionComplitedHandler ActionComplited;
public void OnActionComplited(ActionResult actionResult)
{
if (ActionComplited != null)
{
ActionComplitedEventArgs args = new ActionComplitedEventArgs();
args.ActionResult = actionResult;
ActionComplited(this, args);
}
}
But when trying to sign the dll to the event I cant's see it.
mySeriveInstance.ActionComplited+=... //(I don't get the eventHandler after the dot)
I prefer not to use WCF callback.
The WCF service instance is Single.
What do I do wrong and is there other method to do that?
Thanks.
There are two basic ways you can do this:
1.) You can self-host a WCF service in your client application, and in the call to your server pass in the ip address of the client machine. The server can then construct a proxy and call back to the client when it wants to send it an event
2.) You can poll for events from the server every so often. Give every client an identifier in their service response, and then they can call the server with that identifier every so often. You can use caching on the server side to store a list of undelivered events, and then when a client hits that link you return the oldest event for the client.