I am trying to pass a custom object from self hosted signalr hub server to all the clients, the method in client side not getting invoked .But if the same custom class object is passed from client to server works fine, meaning it invokes the server method.
below is the sample code :
public class ChatHub : Hub
{
public void Send(DataContract message)
{
//below call not reaching to client while passing custom obj
Clients.All.SendMessage(message);
//below string passing works - means invokes client method
Clients.All.SendMsg("test");
}
}
custom class defined in both client and server project via dll:
public class DataContract
{
public string Name
{
get;set;
}
public int Id
{
get;set;
}
}
client side method:
public class SignalRClient
{
HubConnection hubConnection = null;
IHubProxy chat;
public SignalRClient()
{
hubConnection = new HubConnection("https://localhost/");
chat = hubConnection.CreateHubProxy("ChatHub");
}
public void StartConnection()
{
if (hubConnection != null)
{
hubConnection.Start().Wait();
}
chat.On<DataContract>("SendMessage", (stock) =>
{
Console.WriteLine("name {0} id {1}", stock.Name, stock.Id.ToString());
});
chat.On<string>("SendMsg", (message) =>
{
Console.WriteLine(message);
});
}
public void SendMessage(DataContract dd)
{
dd.Name = "test";
chat.Invoke("Send", dd).Wait();
}
public void SendMessage(string msg)
{
chat.Invoke("SendMsg", "Console app", msg).Wait();
}
}
//program.cs
main()
{
SignalRClient client = new SignalRClient();
client.StartConnection();
string msg = null;
while ((msg = Console.ReadLine()) != null)
{
DataContract dd = new DataContract { Name = "arun", Id = 9 };
//below calls reaches to server both string type and custome obj
client.SendMessage(dd);
client.SendMessage("client");
}
}
Any clue on why when calling from server (i.e Clients.All.SendMessage(message); ) not invoking client method when param is custom object.
Thanks in advance.
Related
I have created a chat using SignalR2. The client and server itself works fine. Now, I'm trying to implement a 'users online' function. The server code seems about right, but I'm struggling to make the client receive the data that the server pushes back to the client.
This is the server code below:
public static List<string> Users = new List<string>();
public void Send(string name, string message)
{
// Call the broadcastMessage method to update clients.
Clients.All.broadcastMessage(name, message);
Clients.All.addMessage(name, message);
}
public void SendUserList(List<string> users)
{
var context = GlobalHost.ConnectionManager.GetHubContext<chatHub>();
context.Clients.All.updateUserList(users);
}
public override Task OnConnected()
{
string clientId = GetClientId();
//if (Users.IndexOf(clientId) == -1)
//{
Users.Add(clientId);
//}
SendCount(Users.Count);
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
System.Diagnostics.Debug.WriteLine("Disconnected");
SendCount(Users.Count);
return base.OnDisconnected(stopCalled);
}
private string GetClientId()
{
string clientId = "";
if (Context.QueryString["clientId"] != null)
{
// clientId passed from application
clientId = this.Context.QueryString["clientId"];
}
if (string.IsNullOrEmpty(clientId.Trim()))
{
clientId = Context.ConnectionId;
}
return clientId;
}
public void SendCount(int count)
{
// Call the addNewMessageToPage method to update clients.
var context = GlobalHost.ConnectionManager.GetHubContext<chatHub>();
context.Clients.All.updateUsersOnlineCount(count);
}
Below is the client code for connecting / receiving messages:
public static async void ConnectAsync(RadChat ChatInternal)
{
ChatInternal.Author = new Author(null, Varribles.Agent);
var querystringData = new Dictionary<string, string>();
querystringData.Add("clientId", Varribles.Agent);
Connection = new HubConnection(ServerURI, querystringData);
HubProxy = Connection.CreateHubProxy("chatHub");
//Handle incoming event from server: use Invoke to write to console from SignalR's thread
HubProxy.On<string, string>("AddMessage", (name, message) =>
ChatInternal.Invoke((Action)(() =>
Backend.GET.Messages(ChatInternal)
)));
try
{
await Connection.Start();
Backend.GET.Messages(ChatInternal);
}
catch (System.Net.Http.HttpRequestException)
{
//No connection: Don't enable Send button or show chat UI
return;
}
}
Now, my question is, how can I retrieve the 'Users' list from the server?
Thanks in advance
I'm working on a really simple app running as RFC Server. I installed SAP Netweaver 7.5 trial version. Here is the code to start the server :
private void button2_Click(object sender, EventArgs e)
{
RfcDestinationManager.RegisterDestinationConfiguration(new RfcDestinationConfig());
RfcServerManager.RegisterServerConfiguration(new RfcServerConfig());
Type[] handlers = new Type[1] { typeof(StfcConnectionStaticImpl) };
RfcServer server = RfcServerManager.GetServer("PRD_REG_SERVER", handlers);
server.Start();
}
Then the handling class :
class StfcConnectionStaticImpl
{
// The annotation binds the function (name) to its implementation
[RfcServerFunction(Name = "STFC_CONNECTION")]
public static void StfcConnection(RfcServerContext serverContext, IRfcFunction function)
{
Console.WriteLine("System Attributes: " + serverContext.SystemAttributes.ToString());
function.SetValue("ECHOTEXT", function.GetString("REQUTEXT"));
function.SetValue("RESPTEXT", "NCO3: Hello world.");
}
}
next the Rfc destination config class :
public class RfcDestinationConfig : IDestinationConfiguration
{
public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged;
public bool ChangeEventsSupported()
{
return false;
}
public RfcConfigParameters GetParameters(string destinationName)
{
if ("PRD_000".Equals(destinationName))
{
RfcConfigParameters parms = new RfcConfigParameters();
parms.Add(RfcConfigParameters.AppServerHost, "172.18.3.22");
parms.Add(RfcConfigParameters.SystemNumber, "00");
parms.Add(RfcConfigParameters.User, "developer");
parms.Add(RfcConfigParameters.Password, "Appl1ance");
parms.Add(RfcConfigParameters.Client, "001");
parms.Add(RfcConfigParameters.Language, "EN");
parms.Add(RfcConfigParameters.PoolSize, "5");
parms.Add(RfcConfigParameters.MaxPoolSize, "10");
parms.Add(RfcConfigParameters.IdleTimeout, "600");
return parms;
}
else return null;
}
}
and last the Rfc server class :
public class RfcServerConfig : IServerConfiguration
{
public event RfcServerManager.ConfigurationChangeHandler ConfigurationChanged;
public bool ChangeEventsSupported()
{
return false;
}
public RfcConfigParameters GetParameters(string serverName)
{
if ("PRD_REG_SERVER".Equals(serverName))
{
RfcConfigParameters parms = new RfcConfigParameters();
parms.Add(RfcConfigParameters.GatewayHost, "172.18.3.22");
parms.Add(RfcConfigParameters.GatewayService, "sapgw00");
parms.Add(RfcConfigParameters.ProgramID, "DOT_NET_SERVER");
parms.Add(RfcConfigParameters.RepositoryDestination, "PRD_000");
parms.Add(RfcConfigParameters.RegistrationCount, "5");
return parms;
}
else return null;
}
}
The server start perfectly and my registration in the Gateway is ok.
SAP GATEWAY (SMGW)
The problem coming from Logged-on Client because I only see the external client and not the registered program :
Logged-on Client
My question is why I don't get the Program as Registered Server ?
Is there some SAP configuration to do to allow Program registration ?
If someone can't help me to solve this out, it will be great.
Thank you,
Ronan
I want to Create WebSocket Example in which i do not want to refresh the page for getting latest data.
I Create one Html page in which create one object of websocket.
E.g
ClientSide Implementation
var ws = new WebSocket(hostURL);
ws.onopen = function ()
{
// When Connection Open
};
ws.onmessage = function (evt)
{
// When Any Response come from WebSocket
}
ws.onclose = function (e)
{
// OnClose of WebSocket Conection
}
Server Side Implementation
public class WebSocketManager : WebSocketHandler
{
private static WebSocketCollection WebSocketObj4AddMessage = new WebSocketCollection();
public override void OnOpen()
{
// Do when Connection Is Open
}
public override void OnClose()
{
// Close Connection
}
public override void OnMessage(string message)
{
// When Any Message Sent to Client
}
}
Is I am doing right way to use WebSocket ?
Please help me to clear out in this section.
Here a sample.
First you have to install Asp.net SignalR package along with its dependenies.
You have call the SignalR when the app starts
namespace ABC
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
app.MapSignalR(); <--{Add this line}
}
}
}
You have start the SqlDependency when app start and stop when app stops in the Global.asax file.
string ConnectionString = ConfigurationManager.ConnectionStrings["ConnectionStringsName"].ConnectionString;
protected void Application_Start()
{
SqlDependency.Start(ConnectionString);
}
protected void Application_End()
{
SqlDependency.Stop(ConnectionString);
}
You have to create custom Hubclass extending Hub Base class
public class MessagesHub : Hub
{
[HubMethodName("sendMessages")]
public void SendMessages()
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MessagesHub>();
context.Clients.All.updateMessages();
}
}
Then in the client page, you have add these code in the javascript section
$(function () {
// Declare a proxy to reference the hub.
var notifications = $.connection.messagesHub;
//debugger;
// Create a function that the hub can call to broadcast messages.
notifications.client.updateMessages = function () {
getAllMessages()
};
// Start the connection.
$.connection.hub.start().done(function () {
getAllMessages();
}).fail(function (e) {
alert(e);
});
});
function getAllMessages() {
$.ajax({
url: '../../Notifications/GetNotificationMessages',
.
.
}
The server call this function when there there is any change in the database table using sqlDependency
The getAllMessages() is the controller for your code to handle, that should be shown in the view page and it will be call when the app starts and any change in db
public ActionResult GetNotificationMessages()
{
NotificationRepository notification = new NotificationRepository();
return PartialView("_NotificationMessage");
}
The in model class
public class NotificationRepository
{
readonly string connectionString = ConfigurationManager.ConnectionStrings["InexDbContext"].ConnectionString;
public IEnumerable<Notification> GetAllMessages(string userId)
{
var messages = new List<Notification>();
using(var connection = new SqlConnection(connectionString))
{
connection.Open();
using (var command = new SqlCommand(#"SELECT [NotificationID], [Message], [NotificationDate], [Active], [Url], [userId] FROM [dbo].[Notifications] WHERE [Active] = 1 AND [userId] ='" + userId + "'", connection))
{
command.Notification = null;
var dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
{
connection.Open();
}
var reader = command.ExecuteReader();
while (reader.Read())
{
messages.Add(item: new Notification { NotificationID = (int)reader["NotificationID"], Message = (string)reader["Message"], Url = (string)reader["Url"] });
}
}
}
return messages;
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
MessagesHub message = new MessagesHub();
message.SendMessages();
}
}
}
This well show latest data when the database table is updated. the message will shown at runtime.
Hope this helps
You are on the right path
You can refer this if I am not late ...This is working example
CLIENT SIDE
var ws;
var username = "JOHN";
function startchat() {
var log= $('log');
var url = 'ws://<server path>/WebSocketsServer.ashx?username=' + username;
ws = new WebSocket(url);
ws.onerror = function (e) {
log.appendChild(createSpan('Problem with connection: ' + e.message));
};
ws.onopen = function () {
ws.send("I am Active-" +username);
};
ws.onmessage = function (e) {
if (e.data.toString() == "Active?") {
ws.send("I am Active-" + username);
}
else {
}
};
ws.onclose = function () {
log.innerHTML = 'Closed connection!';
};
}
</script>
<div id="log">
</div>
Server Side in Websocketserver.ashx page
public class WebSocketsServer : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.IsWebSocketRequest)
{
context.AcceptWebSocketRequest(new MicrosoftWebSockets());
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
Add below class in the server side
public class MicrosoftWebSockets : WebSocketHandler
{
private static WebSocketCollection clients = new WebSocketCollection();
private string msg;
public override void OnOpen()
{
this.msg = this.WebSocketContext.QueryString["username"];
clients.Add(this);
clients.Broadcast(msg);
}
public override void OnMessage(string message)
{
clients.Broadcast(string.Format(message));
}
public override void OnClose()
{
clients.Remove(this);
clients.Broadcast(string.Format(msg));
}
add this dll to the above class
using Microsoft.Web.WebSockets;
I donot remeber where I got the reference ...but above code is derived from my current working application
I have application in which I am showing data from sensors using SignalR. It uses ASP.net membership to authenticate the users. It all works fine if I only open one browser window(e.g. Firefox). If I open same website in another browser e.g. Chrome at the same time then signalR connection to firefox browser drops even if the user is different. This is what I am using to broadcast message:
Hub
[Authorize]
public class DataHub:Hub
{
private readonly RealTimeData _sensor;
public DataHub() : this(RealTimeData.Instance) { }
public DataHub(RealTimeData data)
{
_sensor = data;
}
public override Task OnConnected()
{
// _sensor.UserId = Context.ConnectionId; changed to
_sensor.UserId = Membership.GetUser().ProviderUserKey.ToString();
return base.OnConnected();
}
}
public class RealTimeData
{
//User Id
public String UserId { get; set; }
private readonly static Lazy<RealTimeData> _instance = new Lazy<RealTimeData>(() => new RealTimeData(GlobalHost.ConnectionManager.GetHubContext<DataHub>().Clients));// Singleton instance
private IHubConnectionContext Clients;
private void BroadcastDataOfAllSensors(List<SensorDetails> sensor)
{
//Clients.Client(UserId).updateDashboard(sensor);changed to
Clients.User(UserId).updateDashboard(sensor);
}
}
Application Startup
public class StartUp
{
public void Configuration(IAppBuilder app)
{
var idProvider = new UserIdProvider();
GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => idProvider);
app.MapSignalR();
}
}
UserId
public class UserIdProvider : IUserIdProvider
{
public string GetUserId(IRequest request)
{
var userId = Membership.GetUser().ProviderUserKey;
return userId.ToString();
}
}
I would like to implement a pub/sub application with .NET clients, so I'm testing SignalR by means of this minimal code.
This is the server:
namespace Test.SignalRComm.SimpleServer
{
using System.Threading.Tasks;
using log4net;
using SignalR;
using SignalR.Hosting.Self;
using SignalR.Hubs;
using SignalR.Infrastructure;
class Program
{
private static SignalRServer signalRServer = null;
static void Main(string[] args)
{
signalRServer = new SignalRServer();
signalRServer.Start();
System.Console.WriteLine("Press Enter to close...");
System.Console.ReadLine();
signalRServer.Stop();
}
}
public class SignalRServer
{
private string serverUrl = null;
public Server signalRServer = null;
public SignalRServer()
{
serverUrl = #"http://localhost:5001/";
signalRServer = new SignalR.Hosting.Self.Server(serverUrl);
signalRServer.EnableHubs();
}
public void Start()
{
signalRServer.Start();
}
public void Stop()
{
IConnectionManager connManager = signalRServer.DependencyResolver.Resolve<IConnectionManager>();
dynamic clients = connManager.GetClients<SignalRTestHub>();
clients.AddMessage("Test");
signalRServer.Stop();
}
}
public class SignalRTestHub : Hub, IDisconnect
{
private static readonly ILog logger = LogManager.GetLogger(typeof(SignalRTestHub));
public void Register(string token)
{
AddToGroup(token).ContinueWith(task =>
{
if (task.IsFaulted)
logger.Error(task.Exception.GetBaseException());
else
{
string message = string.Format("Client {0} registered with token <{1}>", Context.ConnectionId, token);
logger.Info(message);
}
});
}
public void Unregister(string token)
{
RemoveFromGroup(token).ContinueWith(task =>
{
if (task.IsFaulted)
logger.Error(task.Exception.GetBaseException());
else
logger.InfoFormat("Client {0} unregistered from token <{1}>", Context.ConnectionId, token);
});
}
public Task Disconnect()
{
string message = string.Format("Client {0} disconnected", Context.ConnectionId);
logger.Info(message);
return null;
}
}
}
and this is the client:
namespace Test.SignalRComm.SimpleClient
{
using System.Threading.Tasks;
using log4net;
using SignalR.Client.Hubs;
class Program
{
private static readonly ILog logger = LogManager.GetLogger(typeof(Program));
static void Main(string[] args)
{
SignalRClient client = new SignalRClient("http://localhost:5001/");
client.Start().ContinueWith(task =>
{
if (task.IsFaulted)
{
logger.Error("Failed to start!", task.Exception.GetBaseException());
}
else
{
logger.InfoFormat("Success! Connected with client connection id {0}", client.ConnectionId);
// Do more stuff here
client.Invoke("Register", "Test").ContinueWith(tsk =>
{
if (tsk.IsFaulted)
logger.Error("Failed to start!", tsk.Exception.GetBaseException());
else
logger.Info("Success! Registered!");
});
}
});
System.Console.WriteLine("Press Enter to close...");
System.Console.ReadLine();
client.Invoke("Unregister", "Test").ContinueWith(tsk =>
{
if (tsk.IsFaulted)
logger.Error("Failed to stop!", tsk.Exception.GetBaseException());
else
logger.InfoFormat("Success! Unregistered!");
});
client.Stop();
}
}
public class SignalRClient : HubConnection
{
private static readonly ILog logger = LogManager.GetLogger(typeof(SignalRClient));
IHubProxy hub = null;
public SignalRClient(string url)
: base(url)
{
hub = CreateProxy("Test.SignalRComm.SimpleServer.SignalRTestHub");
}
public Task Invoke(string methodName, params object[] args)
{
return hub.Invoke(methodName, args);
}
public void AddMessage(string data)
{
logger.InfoFormat("Received {0}!", data);
}
}
}
While invoking hub methods from client (Register and Unregister) works fine, I'm not able to call client AddMessage method from hub.
Furthermore the Disconnect method of the hub is never called when a client is closed.
What I'm doing wrong? I'm not able to find any working example.
Edit
Subscribing to hubs events on the client like this:
hub.On<string>("Notify", message => Console.Writeline("Server sent message {0}", message);
and triggering the event on the hub like this:
Clients.Notify("Something to notify");
makes the notifications from server to clients working.
I'm still unable to detect a client disconnection. I implemented the IDisconnect interface on the hub, but when a client connection stops, the Disconnect method on the hub isn't triggered.
Thanks for your help.
Take a look at how to use the .NET client here:
https://gist.github.com/1324342
And API docs here:
https://github.com/SignalR/SignalR/wiki
TL;DR you need to subscribe to specific methods, deriving from the hubConnection doesn't make any magic happen.