Having a problem / lack of knowledge with SignalR , I have a Hub client/server and a separate GUI app with intermittently will connect to the hub and send a message.
I either need the connection to be maintained or to disconnect after the message has been sent.
The problem I run into is that it will always send the first message but then get stuck sending the second message. I am unsure why this is.
public void SignalR_Connect(string message)
{
var connection = new HubConnection("http://site/signalr");
IHubProxy myHub = connection.CreateProxy("chat");
Console.WriteLine("Connection state is : " + connection.State.ToString());
connection.Start().ContinueWith(task =>
{
Console.WriteLine("Attempting to Connect");
if (task.IsFaulted)
{
Console.WriteLine("There was an error opening the connection:{0}", task.Exception.GetBaseException());
}
else
{
Console.WriteLine("Client Connected");
}
}).Wait();
//Sending message
myHub.Invoke("Send", message).ContinueWith(task =>
{
if (task.IsFaulted)
{
Console.WriteLine("There was an error calling send: {0}", task.Exception.GetBaseException());
Console.WriteLine(task.Status.ToString());
}
else
{
Console.WriteLine("Send Complete.");
}
}).Wait();
//Back round to get the next message.
//Method grabs next message in the MSMQ and sends it to SignalR_Connect method.
Read_Queue();
}
I have tried connection.stop() , implementing a close method on the hub to inform the server of the client leaving and setting the GlobalHost.Configuration.ConnectionTimeout but I am still getting the same behaviour.
Related
How can I send a message to my server from, let's say a Razor component?
The situation:
I have a working SignalR (Core) connection with my server.
My client code:
public class StartMySignalR
{
HubConnection connection;
public async void StartSignalRHub()
{
connection = new HubConnectionBuilder()
.WithUrl(new Uri("https://myurl.my/LogOnHub"))
.WithAutomaticReconnect()
.Build();
connection.On<string>("ReceiveMessage", (message) =>
{
//Do some stuff
ii.InsertIntoLog("INFO", "SignalR ID = " + message);
});
//Start SignalR client
await connection.StartAsync();
//Send message to server (test connection).
await connection.InvokeAsync("WelcomeMessage", connection.ConnectionId);
I send a test message to my server, that works fine. I can also send a message back from my server,.. so far so good. But now I want to do that from a Razor component in my OnInitializedAsync() Task. So when my page loads, the test message is sent to my server. There I am stuck. When I try to send the message from my Razor component I receive an error (System.NullReferenceExeption - Object reference not set to an instance of an object) -> connection was null error.
Can somebody put me in the right direction?
When I set the Hubconnection to static it works.
public static HubConnection connection;
Below is my code to connect to the hub.
I used the below code for connecting the hub and send a message.
public ChatService(){
connection = new HubConnection(Services.ServerConstant.BaseUrl);
proxy = ChatServices._connection.CreateHubProxy("HubName");
}
//to start connection
Void async Start(){
var http = new Microsoft.AspNet.SignalR.Client.Http.DefaultHttpClient();
await _connection.Start(new WebSocketTransportLayer(http));
}
//For Connection
Void SendMessage(){
chatServices = DependencyService.Get<IChatServices>();
chatServices.Connect();
connection.Start();
await connection.Send("Test");
}
You are recreating connection to hub every time you send the message. That's wrong approach. Instead you should check connection status and reconnect only in case the connection is lost.
Example
private async Task CheckConnection()
{
if (connection.State == ConnectionState.Connected)
{
return;
}
try
{
await connection.Start();
await proxy.Invoke("Connect");
}
catch (Exception ex)
{
// your exception handler goes here
}
}
I have an infinitely running process that pushes events from a server to subscribed SignalR clients. There may be long periods where no events take place on the server.
Currently, the process all works fine -- for a short period of time-- but eventually, the client stops responding to events pushed by the server. I can see the events taking place on the server-side, but the client becomes unaware of the event. I am assuming this symptom means some timeout period has been reached and the client has unsubscribed from the Hub.
I added some code to reconnect if the connection was dropped, and that has helped, but the client still eventually stops seeing new events. I know there are many different timeout values that can be adjusted, but it's all pretty confusing to me and not sure if I should even be tinkering with them.
try
{
myHubConnection = new HubConnectionBuilder()
.WithUrl(hubURL, HttpTransportType.WebSockets)
.AddMessagePackProtocol()
.AddJsonProtocol(options =>
{
options.PayloadSerializerSettings.ContractResolver = new DefaultContractResolver();
})
.Build();
// Client method that can be called by server
myHubConnection.On<string>("ReceiveInfo", json =>
{
// Action performed when method called by server
pub.ShowInfo(json);
});
try
{
// connect to Hub
await myHubConnection.StartAsync();
msg = "Connected to Hub";
}
catch (Exception ex)
{
appLog.WriteError(ex.Message);
msg = "Error: " + ex.Message;
}
// Reconnect lost Hub connection
myHubConnection.Closed += async (error) =>
{
try
{
await Task.Delay(new Random().Next(0, 5) * 1000);
await myHubConnection.StartAsync();
msg = "Reconnected to Hub";
appLog.WriteWarning(msg);
}
catch (Exception ex)
{
appLog.WriteError(ex.Message);
msg = "Error: " + ex.Message;
}
};
This all works as expected for a while, then stops without errors. Is there something I can do to (1) ensure the client NEVER unsubscribes, and (2) if the connection is lost (network outage for example) ensures the client resubscribes to the events. This client must NEVER timeout or give up trying to reconnect if required.
I have implemented SignalR in my Silverlight 5 application and it's working fine as long as the client stays on-line. But as soon as the network connection drops for more than about 5 seconds, it stops functioning and I can't make it reconnect.
When a client loses the network connection, the Hub's event "OnDisconnected" is triggered.
But on the client side the HubConnection's Closed or StateChanged events are not triggered and the ConnectionState remains Connected. It then tries to make a call to hubproxy.Invoke(), but that will not invoke the client-side method as it would if the network connection stayed alive.
I instantiate the signalr client in App.xaml.xs:
private void Application_UserLoaded(LoadUserOperation operation)
{
//Some checks whether user is logged in
_signalRClient = new SignalRClient();
_signalRClient.RunAsync();
}
.
public class SignalRClient
{
public async void RunAsync()
{
SetHubConnection();
SetHubProxy();
await StartHubConnection();
SendTestSignal();
}
private void SetHubConnection()
{
try
{
_hubConnection = new HubConnection("https://10.1.2.3/HubWeb");
}
catch (WebException ex)
{
LoggerManager.WriteLog(LogType.ERROR, ex.ToString());
}
_hubConnection.Closed += () => TimeoutHelper.SetTimeout(5000, () => _hubConnection.Start());
_hubConnection.StateChanged += (change) => LoggerManager.WriteLog(LogType.DEBUG, String.Format("SignalR Client: Connection State Changed from {0} to {1}", change.OldState, change.NewState));
}
I tried to implement automatic reconnect, as the documentation suggests, by handling the client side Closed event and that starting the hubconnection.
But because the ConnectionState is still "Connected", this event is not triggered and I do not see a way to restart the connection from the client.
What could be the cause of the Connectionstate property of client's hubconnection not changing tot "Disconnected" and why is the Closed event not triggered?
Any help appreciated.
All i am using a quartz schedular for scheduling a job in an asp.net mvc application.This schedular schedules a job after fixed interval of time.
http://quartznet.sourceforge.net/
The service i have created basically runs every minute.It reads the message from the
message que(database in my case) every 1min , sends an email and updates the message sent status
to true.
I am having some problems though.TO be specific the problem is the service sends the same email twice because of the reasons mentioned below.
In some cases the service gets called as soon as an email is send before the db update happens.As The database update does not happen after sending email and service is invoked again,the processed message is again read from the database as unread message and gets resent.
The same message is read again from database.Thus the service ends of sending same message twice.
How do i handle this case in my code.
public void Execute(JobExecutionContext context)
{
List<QueuedEmail> lstQueuedEmail =
_svcQueuedEmail.Filter((x => x.IsSent == false)).Take(NO_OF_MAILS_TO_SEND).ToList();
if (lstQueuedEmail.Count > 0)
{
foreach (var queuedEmail in lstQueuedEmail)
{
try
{
bool emailSendStatus = false;
emailSendStatus = EmailHelper.SendEmail(queuedEmail.From, queuedEmail.To, queuedEmail.Subject,
queuedEmail.Body, queuedEmail.FromName);
QueuedEmail objQueuedEmail =
_svcQueuedEmail.Filter(x => x.Id == queuedEmail.Id).FirstOrDefault();
if (emailSendStatus)
{
objQueuedEmail.IsSent = true;
objQueuedEmail.SentOnUtc = DateTime.UtcNow;
}
else
{
objQueuedEmail.IsSent = false;
if (objQueuedEmail.SentTries == null)
{
objQueuedEmail.SentTries = 1;
}
else
{
objQueuedEmail.SentTries += 1;
}
}
_svcQueuedEmail.Update(objQueuedEmail);
}
catch (Exception)
{
//log error
}
}
}
}
Assuming you have two states for an email: "Pending" and "Sent".
You should add a third an intermediary state called "Sending" and as soon as you read the email from the Queue you should change it's status to something like "Executing" so other threads/services won't get it again.