Weird delay receiving a SignalR callback - c#

The bounty expires in 4 days. Answers to this question are eligible for a +50 reputation bounty.
binks wants to draw more attention to this question.
I'm experiencing a weird issue, where a callback using SignalR sent to multiple clients gets delayed for some of the clients.
As you can see there's a full 7 second delay between client A receiving the callback and client B receiving the callback.
There is a "master" client does an invoke, at the end of a timer:
vm.bettingconnection
.invoke("MoveToNextRound", gameId)
.catch(function (err) {
return console.error(err.toString());
});
"vm" is a VueJS object
var vm = new Vue({
el: '#gamesquares',
data: function () {
return {
rawgamedata: [],
connection: "",
bettingconnection: "",
scorepredictShow: true,
boardShow: false,
timerShow: false,
expectationShow: false,
restseconds: 0,
roundseconds: 0,
restsecondsleft: 0,
roundsecondsleft: 0,
roundsleft: 0,
currentround: 0,
gamemode: 0,
estimatedpoints: 0,
scoreindex: 0,
currentscore: 0,
targetscore: 0
};
},
The invoked endpoint has very simple logic:
public async Task MoveToNextRound(Guid gameId)
{
int roundNumber = _gameAdministration.NextRound(gameId);
//need a try catch //game not found
await Clients.Groups(gameId.ToString()).MovedToNextRound(roundNumber);
}
Inside NextRound is this (also very simple)
public int NextRound(Guid gameId)
{
int roundNumber = _cache.Get<int>(gameId.ToString() + "-roundnumber");
roundNumber++;
_cache.Set(gameId.ToString() + "-roundnumber", roundNumber);
return roundNumber;
}
So this bit here is where I assume the problem lies:
await Clients.Groups(gameId.ToString()).MovedToNextRound(roundNumber);
Why is that callback is taking a while to get to some of the clients?

Related

Ajax request from Web Application to a local TCP Listener

In advance, sorry for the newbie questions but I need to get some clarity.
I am working on a TCP listener using c# and .net core.
The purpose of this project is to create a server that listens for JSON data, processes it and then sends it to a local printer.
The JSON data is sent from a web application using JavaScript (Ajax) on the same local network.
Everything works fine when the Ajax call is made from a simple html/js page, but not when it is embedded in my web application (asp net core mvc).
The data received is completely corrupted (or encrypted?).
I think the problem is that IIS uses a "local" ssl certificate and my TCP listener server does not have one.
So the transferred data is encrypted and cannot be understood by the server.
I tried to set the "crossdomain" property of my ajax to true, but with no result.
Can you confirm that the ssl certificate could be the cause of the problem?
The server was made using the nugget package "SimpleTCP", what would you advise me to use instead for this type of project?
I have read about SslStream, but before I rewrite the server I would like to be sure what I am doing...
Does the certificate I have to use on my server have to be the same as the one used by IIS? (I guess so if I want to decrypt the data...)
Thanks in advance for your time and interest!
Edit :
Here is the Ajax call, from the web application.
let dataToSend = [
{label : "Soft", price : 2, quantity : 1},
{label : "Beer", price : 4, quantity : 2},
{label : "Coffee", price : 2, quantity : 1}
];
$.ajax({
type: 'POST',
dataType: 'json',
url: 'http://192.168.1.53:8910',
crossDomain: true,
async: true,
data: JSON.stringify(dataToSend),
success: function(response) {
console.log(response);
},
error: function(err) {
console.log(err);
}
});
And here is the event on the tcp listener which is triggered when data is received:
private void Server_DataReceived(object sender, SimpleTCP.Message e)
{
//this.Console is a textbox
this.Console.Invoke((MethodInvoker)delegate ()
{
int indexDelimiter = e.MessageString.IndexOf(this.JsonResponseDelimiter);
if(indexDelimiter < 0)
{
this.Log("\r\nNo Json data found...");
return;
}
string response = e.MessageString.Substring(indexDelimiter);
this.Log(response);
try
{
List<TicketLineDTO> ticketLineDTOs = JsonConvert.DeserializeObject<List<TicketLineDTO>>(response);
e.ReplyLine("Message correctly transfered.");
if (ticketLineDTOs != null && ticketLineDTOs.Count > 0)
{
this.PrintReceivedData(ticketLineDTOs);
}
}
catch (Exception ex)
{
this.Log("\r\nWrong data... " + ex.Message);
}
});
}
And here is the content of e.MessageString :
"\u0016\u0003\u0001\u0002\0\u0001\0\u0001�\u0003\u0003)��\r1�A�NT�*g�~2Z�j\t\u0005�)�N���렜 v�xZ#�E\v;D�!}c\u0003�x#O\u0018\u0016���#x��\t%\0 ��\u0013\u0001\u0013\u0002\u0013\u0003�+�/�,�0̨̩�\u0013�\u0014\0�\0�\0/\05\u0001\0\u0001���\0\0\0\u0017\0\0�\u0001\0\u0001\0\0\n\0\n\0\bJJ\0\u001d\0\u0017\0\u0018\0\v\0\u0002\u0001\0\0#\0\0\0\u0010\0\u000e\0\f\u0002h2\bhttp/1.1\0\u0005\0\u0005\u0001\0\0\0\0\0\r\0\u0012\0\u0010\u0004\u0003\b\u0004\u0004\u0001\u0005\u0003\b\u0005\u0005\u0001\b\u0006\u0006\u0001\0\u0012\0\0\03\0+\0)JJ\0\u0001\0\0\u001d\0 <۠xv��\u0002KL\0\u0006?a�����.\u000f�\u001b��_(B\u0005\u000f\0-\0\u0002\u0001\u0001\0+\0\a\u0006::\u0003\u0004\u0003\u0003\0\u001b\0\u0003\u0002\0\u0002Di\0\u0005\0\u0003\u0002h2��\0\u0001\0\0\u0015\0�\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"

ASP.NET Web API very slow while controller code is fast

asp.net .net 4.7 web API
I am accessing a ASP.NET web API via jQuery.
JQuery collects a number of ids and sends one ajax request per id.
If there is 1 id the query is processed in 6-10ms
If there is more than 1 it can take 500-1000 ms as seen in browser web dev timing or in IIS log access log files. A stopwatch in controller is consistent for all queries below 10ms.
Same issue on both IIS prod server and local Dev machine.
function dashboardLoader() {
var tcs = $(".dashboardtc");
for (var i = 0; i < tcs.length; i++) {
var fid = $(tcs[i]).attr("data-fid");
$.ajax({
url: '/ctl/dashboardfeature/' + fid,
type: 'GET',
cache: false,
contentType: "application/json",
success: function (d1) {
adjustDashBoardCell(d1);
},
error: function (result) {
console.log(result.Message);
}
});
}
}
API:
[Authorize]
[Route("ctl/dashboardfeature/{fid}")]
[HttpGet]
public async Task<dashboardFeaturePayload> GetDashboardFeature(string fid)
{
try
{
var timer = new Stopwatch();
timer.Start();
if (!User.Identity.IsAuthenticated) return null;
string un = User.Identity.Name;
int fID = fid.val();
string rtn = await Task.FromResult<string>(DashboardCode.GetDashboardFeatureAPI(fID, true));
timer.Stop();
TimeSpan timeTaken = timer.Elapsed;
System.Diagnostics.Debug.WriteLine(timer.Elapsed.TotalMilliseconds.ToString());
return new dashboardFeaturePayload(fID, rtn);
}
catch (Exception ex)
{
AdminTask.ExceptionLoging(ex);
return new dashboardFeaturePayload(fid.val(), "ERROR");
}
}
Would appear to be link to the ability of IIS to process multiple requests arriving in the same time.
Web Dev Timing:
VS Output stopwatch:

How to correctly run an exe file on a remote server using ASP.NET MVC web application?

I'm new to C#, ASP.NET MVC, and programming in general. Got a task during the internship to write a web application that will let people run scripts with .exe/.lnk extension on a remote server and receive notifications on completion.
I've done research but at the moment completely stuck with the following issue. The task itself creates a lot of technical questions, but I'll try to narrow it down to two:
The button doesn't trigger the controller. For the table creation used https://datatables.net/. Browser doesn't throw any problems while rendering. Also, that code is a cut from an actual table:
$(document).ready(function () {
dataTable = $("#interfaceTable").DataTable({
"ajax": {
"url": "/Interface/GetData",
"type": "GET",
"datatype": "json"
},
"columns": [
{
"render": function () {
return "<a class='btn btn-outline-dark btn-sm' onclick= location.href = '#Url.Action("InterfaceRuntime", "Interface")'><i class='fas fa-play-circle'></i> Run</a>";
},
],
});
});
If I try to access the controller directly passing an URL(Localhost:~/Interface/interfaceruntime) then the browser throws an exception:
[HttpGet]
public ActionResult InterfaceRuntime()
{
ProcessStartInfo Info = new ProcessStartInfo()
{
FileName = #"C:\Users\Some.User\Hardcode\Path\to\a\file.exe",
UseShellExecute = false,
CreateNoWindow = true,
LoadUserProfile = true,
};
Process InterfaceProcess = new Process();
try
{
InterfaceProcess.StartInfo = Info;
InterfaceProcess.Start();
InterfaceProcess.WaitForExit();
return Json(new { success = true, message = "Executed successfully"}, JsonRequestBehavior.AllowGet);
}
catch (Exception e)
{
return Json(new { success = false, message = e });
}
}
The exception itself:
[InvalidOperationException: This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.]
It seems that the web request is blocked somewhere else and has nothing in common with the Json request. Would appreciate any help with that.

How to handle session in asp.net mvc

How can I do this in Asp.Net MVC?
Activity Timer : When user navigates on the page (means doing something that calls ActionResult) the timer will reset.
When the user doesn't do any activity in more than 15 minutes, he will be prompted and be asked "Are you still there?" (Yes/LogOut), if he click yes, then activity timer will go back to zero, and starting counting again.
This activity timer must be unique per user and must be destroy upon logging out.
PLEASE PLEASE! Be PATIENT TO ME! I don't know how to this.
I had posted this question but I didn't get any answer that solves this problem. So I plan to do it from the start, and I need some help/guide to do it properly.
Any reference links or tutorials will be much appreciated!
I would handle this on the client. Create an object to encapsulate the functionality.
Something like:
var UserInactivityMonitor = UserInactivityMonitor || {};
UserInactivityMonitor = (function (module) {
var inactivityIndex;
var promptIndex;
var timer;
module.startInactivityMonitor = function () {
module.timerTick();
};
module.timerTick = function () {
inactivityIndex--;
if (inactivityIndex === 0) {
module.fireInactivityAlert();
}
if (inactivityIndex === promptIndex) {
module.fireIdlePrompt();
}
timer = setTimeout(module.timerTick, 1000);
};
module.fireIdlePrompt = function () {
var response = confirm('are you stil there?');
if (response === true) {
module.resetInactivityIndex();
}
};
module.resetInactivityIndex = function () {
inactivityIndex = 15;
promptIndex = 5;
};
module.fireInactivityAlert = function () {
alert('Inactivity alert!');
};
module.initialize = function () {
module.resetInactivityIndex();
module.startInactivityMonitor();
};
return module;
})(UserInactivityMonitor || {});
Set inactivityIndex to the number of seconds that will pass before the inactivity event fires. Set promptIndex to the number of seconds remaining when the user will be prompted if they are still there. The code above sets the inactivity timeout to 15 seconds and a idle prompt will be invoked at the 5 second remaining mark.
On page load start the inactivity timer:
$(function () {
UserInactivityMonitor.initialize();
});
On any AJAX request, reset the counter:
$("#fooButton").on('click', function () {
$.ajax(
{
url: $("#buttonClickPostUrl").val(),
data: {
someData: 'data'
},
type: 'POST',
complete: function () {
UserInactivityMonitor.resetInactivityIndex();
}
});
});
If the server is maintaining session state then you will want to make a request back to the server to kill the session and optionally direct the browser to the appropriate page for the event. You would do this in the fireInactivityAlert() function.

JSONP + ASP.NET - Response is incomplete

We have been wrestling with the confines of ASP.NET trying to get JSONP working. We're trying to check whether a file exists on a different server and return a boolean value. The function is called on jquery's ready() function, so it should happened after all DOM elements are loaded.
We've used the HTTPModule request/response rewriter linked here:
http://www.codeproject.com/KB/webservices/ASPNET_JSONP.aspx
The AJAX call:
function CheckFileExists() {
var _FileID = $('#FileID').val();
var button = $('#btnViewFiles');
button.val('Checking...').css('color', '');
$.ajax({
type: "GET",
url: localAdminUrl + "WebServices.asmx/CheckFileExists",
data: { FileID: _FileID },
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
success: function (data, textStatus, jqXHR) {
if (data.d == true) {
button.attr('onClick', 'ViewFiles(_FileID,false);').removeAttr('disabled').val('View documents').css('color', '#22CA00');
} else {
button.val('No documents').css('color', '#DD3BB3').removeAttr('onClick').attr('disabled', 'disabled');
}
},
error: function (jqXHR, textStatus, errorThrown) {
button.val('Error occurred').css('color', '#DD3BB3').removeAttr('onClick').attr('disabled', 'disabled');
}
});
}
Now, for some reason the response occasionally decides to omit the end parentheses and semicolon, leaving an incomplete response, and JSON crying "parsererror".
example:
jQuery<numbers>_<numbers>({"d":false}
instead of the expected:
jQuery<numbers>_<numbers>({"d":false});
The baffling thing is that it only happens occasionally - some requests end up complete and parse correctly. What on earth is going on?
I've tried rewriting the HTTPModule such that the response is written once instead of three times:
public override void Write(byte[] buffer, int offset, int count)
{
var b1 = Encoding.UTF8.GetBytes(_context.Request.Params["callback"] + "(");
var b2 = Encoding.UTF8.GetBytes(");");
byte[] finalResponse = new byte[b1.Length + buffer.Length + b2.Length];
b1.CopyTo(finalResponse,0);
buffer.CopyTo(finalResponse, b1.Length);
b2.CopyTo(finalResponse, b1.Length + buffer.Length);
_responseStream.Write(finalResponse, 0, finalResponse.Length);
/* Old way
_responseStream.Write(b1, 0, b1.Length);
_responseStream.Write(buffer, offset, count);
var b2 = Encoding.UTF8.GetBytes(");");
_responseStream.Write(b2, 0, b2.Length);
*/
}
Doesn't seem to have helped though.
It turns out the GZIPStream compression module which we use is buggy, see here: GZipStream And DeflateStream will not decompress all bytes
We've removed the module from use for the time being and the responses are now being returned consistently complete.

Categories

Resources