SignalR works slow in UWP and fast in console application - c#

I have a SignalR server which sends certain messages to all the clients connected to it. I have created two sample clients one in UWP and another one is a simple console application in C#. I simply log a message once the client's method is called from SignalR.
Dramatically, the console application logs the data as soon as the server sends, but the UWP application adds a delay of about 6-30 seconds in it. Although it triggers frequently sometimes, it is able to reproduce the issue 6 out of 10 times.
Below is the code for the UWP client, similarly, I have logged message in console application.
async Task SetupSignalR()
{
var conn = new HubConnection(baseUrl);
Writer.Text += (string.Format("Creating hub proxy with :{0}\n", baseUrl));
var proxy = conn.CreateHubProxy("PumpStatusHub");
Writer.Text += "Starting Connection\n";
try
{
conn.Start().Wait();
Writer.Text += "Connection started\n";
proxy.Invoke("OpenPortReading").Wait();//, UserName, TextBoxMessage.Text);
Writer.Text += "Port invoked\n";
proxy.On<string>("ReadUdpData", OnMessage);
}
catch (HttpRequestException ex)
{
Writer.Text += "Unable to connect to server: Start server
before connecting clients.\n";
Writer.Text += ex.Message + "\n";
}
catch (Exception ex)
{
Writer.Text += ex.Message + "\n";
Task.Delay(3000).Wait();
SetupSignalR().Wait();
}
}
private void OnMessage(string obj)
{
Windows.ApplicationModel.Core.CoreApplication.MainView.
Dispatcher.RunAsync(CoreDispatcherPriority.High, (DispatchedHandler)(() =>
{
Writer.Text += string.Format("Message received: {0}\n"
, counter++);
}));
}
Any help would be highly appreciated. Thanks in advance.

I got this fixed by collaborating with SignalR developers and found an interesting thing that on using Server sent events as transport there was an issue with SignalR for UWP client which they are fixing.
I resolved the issue by using Long polling transport as Windows 7 does not support WebSockets.

Related

Xamarin Forms Push Notifications using Azure Messaging Hub not working in release mode

I added a functionality to my Xamarin Forms App allowing it to receive Notifications from Azure.
Everything works fine in debug mode, but in release mode, the App crashes when I receive a notification.
I got a logger working with Adb to see the exception. The code I am using is the following:
public void OnPushNotificationReceived(Context context, INotificationMessage message)
{
try
{
var msgData = message.Data;
if (msgData.ContainsKey("EventType"))
{
try
{
if (AllowStoreNotification(msgData["VirtualStoreId"], msgData["EventType"]))
{
SendNotification(message.Title, message.Body);
}
}
catch (KeyNotFoundException ex)
{
new TrackEvent("Could not deliver notification. Parameter error.")
.AddParameter("exception", ex.Message.ToString())
.Send();
}
}
}
catch (Exception ex)
{
Log.Error("Notification", ex.Message);
}
void SendNotification(string title, string body)
{
var notification = new NotificationCompat.Builder(context, "PushNotifications")
.SetContentTitle(title)
.SetContentText(body)
.SetSmallIcon(Resource.Drawable.logo_pink_circle)
.SetAutoCancel(true)
.SetDefaults((int)NotificationDefaults.All)
.SetPriority((int)NotificationPriority.High)
.Build();
if (_notificationManager is null)
{
NotificationManagerCompat.From(context).Notify(0, notification);
}
else
{
_notificationManager.Notify(0, notification);
}
}
}
The _notificationManager is null for version Build.VERSION.SdkInt >= BuildVersionCodes.O.
The exception from de ADB log adb logcat Notification:E *:S:
Notification: no non-static method "Lcom/microsoft/windowsazure/messaging/notificationhubs/BasicNotificationMessage;.getData()Ljava/util/Map;"
Anyone knows how to fix this?
I figured out how to make it work using the skip linking assembly.
The issue is the certificate you uploaded to azure, it's just for development, not for production
You have a few options:
Change the certificate once you move to production
2 clouds, one for development and another for production.
Or just compile your app as production every time you want to test notifications

C# TcpListener - client number limited

Dear Stack Overflow Community,
i am currently developing an online TCG in C#. The server runs perfectly fine on my own machine (quad-core, octa-thread Windows 7). I could connect 12 clients without problem. But when I launch it on a server, the maximum amount of clients becomes limited to the number of processor cores on the machine. I ran the code on a single-core Windows 2016 Server and could not connect more that one client to start a game. Then I ran the server on a quad-core Windows 2012 Server and could only connect four clients and start two games. Any further clients got completely ignored until someone disconnects. Then the new client gets accepted and the server crashes.
The server is a MS Visual Studio 2015 Windows Forms Application with .NET Framework 4.0. The Windows Server machines have .NET Framework 4.0 and my own machine has version 4.5.
I will gladly provide any additional information you may require and answer all your questions.
Server code in C#:
public void Init()
{
try {
server = new TcpListener(IPAddress.Any, port);
server.Start();
serverRunning = true;
server.BeginAcceptTcpClient(AcceptTcpClient, server);
OutputTB.Text = "server has been started on port " + port.ToString();
}
catch (Exception e) {
OutputTB.Text = "socket error: " + e.Message;
}
}
private void AcceptTcpClient(IAsyncResult newClient)
{
if (!serverRunning)
return;
server.BeginAcceptTcpClient(AcceptTcpClient, server);
TcpListener listener = (TcpListener)newClient.AsyncState;
ServerClient client = new ServerClient(listener.EndAcceptTcpClient(newClient));
Send("SWHO", client);
connectedClients.Add(client);
Invoke((MethodInvoker)delegate {
ClientListBox.Items.Add("Waiting for authentification...");
});
NetworkStream stream = client.tcp.GetStream();
StreamReader reader = new StreamReader(stream, true);
while (client.connected && serverRunning) {
if (stream.DataAvailable) {
string data = reader.ReadLine();
if (data != null)
OnIncomingData(client, data);
}
}
Invoke((MethodInvoker)delegate {
if (client.authenticated)
ClientListBox.Items.Remove(client.playerName);
else
ClientListBox.Items.Remove("Waiting for authentification...");
});
Send("SDISC", client);
waitingClients.Remove(client);
connectedClients.Remove(client);
client.tcp.Close();
}
private void OnIncomingData()
{
//process client data
}
Thread pool exhaustion it was! Big thanks to itsme86 and usr for the helpful tips. Now the code looks like this:
private void AcceptTcpClient(IAsyncResult ar)
{
server.BeginAcceptTcpClient(AcceptTcpClient, server);
Task.Run(() => ListenToIncomingData(IAsyncResult ar);
}
There is one thing I'm curious about: doesn't the asynchronous call also consume a thread? how come there are enough resources to handle it but not enough to handle the unfinished callback?

Can't establish connection using StreamSocket (universal windows)

Im trying to follow this code sample from microsoft, who is a basic code for sending/receiving data over network from windows 10 computer/phone.
Im on VS2015, i have a phone on W10 and my computer also.
The problem is that my application seems to create packet and send one to establish the connection (i have seen this packet with wireshark), but i never received it on the server side.
Here is code to listen port from the actual internet connection available and wait for a connection :
public static async void StartServer()
{
try
{
StreamSocketListener listener = new StreamSocketListener();
//ConnectionProfile internetConnectionProfile = NetworkInformation.GetInternetConnectionProfile();
//await listener.BindServiceNameAsync("5043", SocketProtectionLevel.PlainSocket, internetConnectionProfile.NetworkAdapter);
listener.ConnectionReceived += OnConnection;
await listener.BindServiceNameAsync("5043");
Debug.WriteLine("Server Started !");
}
catch (Exception)
{
Debug.WriteLine("Error StartServer Method !");
}
}
The method "OnConnection" is never reach cause the event "ConnectionReceived" is never called.
Here is the code to establish connection (the string ipDestination contain the internet ip address from my phone for example, that i get from checkip.dyndns.org) :
private static StreamSocket socket;
public static async void Connect(string ipDestination)
{
try
{
//Destination Ip address
HostName host = new HostName(ipDestination);
ConnectionProfile internetConnectionProfile = NetworkInformation.GetInternetConnectionProfile();
socket = new StreamSocket();
socket.Control.KeepAlive = true;
await socket.ConnectAsync(host, "5043");
//EXCEPTION RAISE HERE after a moment "System.Runtime.InteropServices.COMException, cant join destination.
Debug.WriteLine("Connected !");
}
catch (Exception)
{
Debug.WriteLine("Erreur Connect Method !");
}
}
I think i should miss something but i dont know why and im block at this part since a long and can't continue my project...
I apologize for the bad english I try to make my best :)
Update from comments :
As Jay Zuo suggested, i have try to use local address on private
network and it works, i can establish connection, send and receive
data without problems... So the problem come when i use internet IP
address, and i still can't figure why...
As Kiewic suggested, i have simplify my code and commented the
precedent version.

restarting services using SMSlib issues

I am currently facing a problem related to SMSlib for .NET library (you can download it at http://www.smslib.org/)
btw I used SendMessage example (you can find it in ...\Examples\SendMessage) found in the library, and tried to compile and run it using VS2012...it worked fine , but it never succeeded when I tried to restart the services again after adding a little bit code to restart the services into it...
Do you know how to make the services restart properly?
btw part of the code is as follows :
try
{
Console.WriteLine("Example: Read messages from a serial gsm modem.");
Console.WriteLine(Library.getLibraryDescription());
Console.WriteLine("Version: " + Library.getLibraryVersion());
// Start the COM listening thread.
new Thread(new ThreadStart(com1.Run)).Start();
// Lets set some callbacks.
srv.setInboundMessageNotification(new InboundNotification());
srv.setCallNotification(new CallNotification());
srv.setGatewayStatusNotification(new GatewayStatusNotification());
// Create the Gateway representing the serial GSM modem.
// Due to the Comm2IP bridge, in SMSLib for .NET all modems are considered IP modems.
IPModemGateway gateway = new IPModemGateway("modem.com14", "127.0.0.1", 12000, "Huawei","E173");
gateway.setIpProtocol(ModemGateway.IPProtocols.BINARY);
// Set the modem protocol to PDU (alternative is TEXT). PDU is the default, anyway...
gateway.setProtocol(AGateway.Protocols.PDU);
// Do we want the Gateway to be used for Inbound messages?
gateway.setInbound(true);
// Do we want the Gateway to be used for Outbound messages?
gateway.setOutbound(true);
// Add the Gateway to the Service object.
srv.addGateway(gateway);
// Similarly, you may define as many Gateway objects, representing
// various GSM modems, add them in the Service object and control all of them.
// Start! (i.e. connect to all defined Gateways)
srv.startService();
// Printout some general information about the modem.
Console.WriteLine();
Console.WriteLine("Modem Information:");
Console.WriteLine(" Manufacturer: " + gateway.getManufacturer());
Console.WriteLine(" Model: " + gateway.getModel());
Console.WriteLine(" Serial No: " + gateway.getSerialNo());
Console.WriteLine(" SIM IMSI: " + gateway.getImsi());
Console.WriteLine(" Signal Level: " + gateway.getSignalLevel() + "dBm");
Console.WriteLine(" Battery Level: " + gateway.getBatteryLevel() + "%");
Console.WriteLine();
// Send one message.
// Remember to change the recipient!
OutboundMessage msg = new OutboundMessage("0952998989", "Hello from SMSLib for .NET");
srv.sendMessage(msg);
Console.WriteLine(msg);
Console.WriteLine("Press <ENTER> to terminate...");
Console.In.ReadLine();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
}
finally
{
com1.Stop();
srv.stopService();
// Start! (i.e. connect to all defined Gateways)
srv.startService();
new Thread(new ThreadStart(com1.Run)).Start();
}
You should not call com1.Stop(); until you're completely done with starting/stopping the service. Just leave the listener active.
E.g.
finally
{
srv.stopService();
srv.startService();
srv.stopService();
srv.startService();
srv.stopService();
srv.startService();
srv.stopService();
srv.startService();
srv.stopService();
// ... and finally ...
com1.Stop();
}

Using Web API for a Windows Service to Receive Commands and Perform Tasks via Polling?

I have a project where I need to create a windows service that, when instructed via a command, will perform various tasks. This server would run on multiple servers and would effectively perform the same kind of tasks when requested.
For example, I would like to have a Web API service that listens for requests from the servers.
The service running on the server would send a query to Web API every 25 secs or so and pass to it its SERVERNAME. The Web API logic will then look up the SERVERNAME and look for any status updates for various tasks... I.E., if a status for a DELETE command is a 1, the service would delete the folder containing log files... if a status for a ZIP command is a 1, the service would zip the folder containing log files and FTP them to a centralized location.
This concept seems simple enough, and I think I need a nudge to tell me if this sounds like a good design. I'm thinking of using .NET 4.5 for the Windows Service, so that I can use the HttpClient object and, of course, .NET 4.5 for the Web API/MVC project.
Can someone please get me started on what a basic Web API woudld look like provide status updates to the Windows services that are running and issue commands to them...
I'm thinking of having a simple MVC website that folks will have a list of servers (maybe based on a simple XML file or something) that they can click various radio buttons to turn on "DELETE", "ZIP" or whatever, to trigger the task on the service.
I do something similar. I have a main Web API (a Windows Service) that drives my application and has a resource called /Heartbeat.
I also have a second Windows Service that has a timer fire every 30 seconds. Each time the timer fires it calls POST /heartbeat. When the heartbeat request is handled, it goes looking for tasks that have been scheduled.
The advantage of this approach is that the service makes the hearbeat request is extremely simple and never has to be updated. All the logic relating to what happens on a heartbeat is in the main service.
The guts of the service are this. It's old code so it is still using HttpWebRequest instead of HttpClient, but that's trivial to change.
public partial class HeartbeatService : ServiceBase {
readonly Timer _Timer = new System.Timers.Timer();
private string _heartbeatTarget;
public HeartbeatService() {
Trace.TraceInformation("Initializing Heartbeat Service");
InitializeComponent();
this.ServiceName = "TavisHeartbeat";
}
protected override void OnStart(string[] args) {
Trace.TraceInformation("Starting...");
_Timer.Enabled = true;
_Timer.Interval = Properties.Settings.Default.IntervalMinutes * 1000 * 60;
_Timer.Elapsed += new ElapsedEventHandler(_Timer_Elapsed);
_heartbeatTarget = Properties.Settings.Default.TargetUrl;
}
protected override void OnStop() {
_Timer.Enabled = false;
}
private void _Timer_Elapsed(object sender, ElapsedEventArgs e) {
Trace.TraceInformation("Heartbeat event triggered");
try {
var httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(_heartbeatTarget);
httpWebRequest.ContentLength = 0;
httpWebRequest.Method = "POST";
var response = (HttpWebResponse)httpWebRequest.GetResponse();
Trace.TraceInformation("Http Response : " + response.StatusCode + " " + response.StatusDescription);
} catch (Exception ex) {
string errorMessage = ex.Message;
while (ex.InnerException != null) {
errorMessage = errorMessage + Environment.NewLine + ex.InnerException.Message;
ex = ex.InnerException;
}
Trace.TraceError(errorMessage);
}
}
}
You can do it with ServiceController.ExecuteCommand() method from .NET.
With the method you can sand custom command to windows' service.
Then in your service you need to implement ServiceBase.OnCustomCommand() to serve incomming custom command event in service.
const int SmartRestart = 8;
...
//APPLICATION TO SEND COMMAND
service.ExecuteCommand(SmartRestart);
...
//SERVICE
protected override void OnCustomCommand(int command)
{
if (command == SmartRestart)
{
// ...
}
}

Categories