Server Sent Events not sent ASP.Net 4 - c#

My server-sent events are not sending anymore. This use to work perfectly and now something has changed and it might be that I am running this as an ASP.Net 4 application. I'm using a pretty standard iHTTPRequest Handler with a loop, a little threading timeout, and around I go, writing messages like this:
A Message - Note: the reason for parsing the message the way I do below, is I wasn't sure if there was a max message length, so in order to elminate this as a potential problem I broke it out. Well forget this bit anyways, because I'm testing now with the most basic message "alive" so it never hits this.
public static void WriteClientMessage(this HttpResponse Response, string Message)
{
if (Message.Length > 50)
{
int start = 0;
int length = 50;
while (length > 0)
{
Response.Write("data: {0}\n", Message.Substring(start, length));
start = start + length;
length = Message.Substring(start, (Message.Substring(start).Length >= length) ? length : Message.Substring(start).Length).Length;
}
}
else
{
Response.Write("data: " + Message);
Response.Write("\n");
}
Response.Write("\n");
Response.Flush();
}
An Event
public static void WriteClientEvent(this HttpResponse Response, string EventName)
{
Response.Write("event: {0}\n", EventName.TrimNewLine());
Response.Write("data: \n\n");
Response.Flush();
}
Something else to note and I think this is really important is that eventually the message do come, but they come all at once, as if they are buffered. So I've played with this, both enable and disable buffering. I've even investigated to make sure that my dynamic content isn't being compressed, although I'm not confident I have this right, but pretty sure that it isn't. I will investigate this further if someone says that for sure it is and this is my problem
So what is it? Is this a .Net 4ism?
**UPDATE - Insert Minimal Sample here - **
I've added a sample of the script here: http://live.meetscoresonline.com/test-sse.aspx
This app loops 10 times and then breaks out of the loop. This is the actual SSE service, so you should get the result directly to your browser, at least in chrome, FF tries to download the file, and haven't tested the other browsers. What I expect to see is data: alive to apear in the browser as it happens, instead nothing appears until the script terminates and then all data: alive events appear. I've tested SSE this way before so I know this works (or use to work). Here is this test code. Am I missing something?
UPDATE: I commented out the break to demonstrate a new behavior. If you wait about 20 or 30 loops, the real-time streaming begins and continues as expected. So what is this initial pause?
public class TestSSE : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/event-stream";
var itt = 0; ;
while (true)
{
if (!context.Response.IsClientConnected)
break;
/* **** UPDATE: REMOVED THE BREAK. STREAMING BEGINS AFTER ABOUT THE 20TH OR 30TH LOOP ****/
// if (itt++ > 10)
// break;
context.Response.Write("data: alive {0}\n\n", DateTime.Now.ToLongTimeString());
context.Response.Flush();
System.Threading.Thread.Sleep(2000);
}
}
}

Looking at the Network tab in Google Chrome developer tools reveals quite a lot from your http://live.meetscoresonline.com/test-sse.aspx
There are no SSE being generated at all - to see this click on the Others button under Network, this is where you would normally be able to track the SSE data stream
I use the following code in my SSE's with a simple HTTPListener and it works well without the delays you mentioned, and always shows up correctly across browsers when using this polyfill
res.AddHeader("Content-Type", "text/event-stream")
res.AddHeader("Cache-Control", "no-cache")
res.AddHeader("Access-Control-Allow-Origin", "*")
res.KeepAlive = True

Related

C#/Xamarin List Emptying Itself

I'm working in C#/Xamarin on the Android portion of a cross-platform PCL solution - I'm very new to Xamarin and mobile dev in general.
In a loop, I'm trying to query a REST service for some geoinformation (which works fine), deserialise the result into an object (also works fine) and then add said object to a list (works fine once). The problem I have is that every time the method getting the deserialised object returns, the collection for them has magically been emptied (Count is 0).
This is where the list lives:
List<Thingy> thingyList = new List<Thingy>();
//Setting some variables
//.
//.
using (HttpClient client = new HttpClient())
{
//Positive offset loop
for (double latUnderTest = Lat; latUnderTest <= latOffsetCoordsMax; latUnderTest += latOffset3M)
{
//Bound to our max coords
latUnderTest = latUnderTest > latOffsetCoordsMax ? latOffsetCoordsMax : latUnderTest;
for (double longUnderTest = Long; longUnderTest <= longOffsetCoordsMax; longUnderTest += longOffset3M)
{
//Bound to our max coords
longUnderTest = longUnderTest > longOffsetCoordsMax ? longOffsetCoordsMax : longUnderTest;
//Don't query areas we've already done
if (HasLocationBeenQueried(latUnderTest, longUnderTest))
{
continue;
}
Thingy thingy = await GetThingyForCoords(latUnderTest, longUnderTest, client);
if (thingy != null)
{
thingyList.Add(thingy);
AdjustQueriedArea(latUnderTest, longUnderTest);
}
}
}
//Negative offset loop, not reached for the purpose of this
//.
//.
return thingyList;
}
Yes, the loops are a bit disgusting but this was just meant to be a quick and dirty first run. Anyway, this is the method making the request:
public async Task<Thingy> GetThingyForCoords(double Lat, double Long, HttpClient Client)
{
try
{
using (HttpResponseMessage resp = await Client.GetAsync(aUrlIKnowWorks))
{
return resp.IsSuccessStatusCode ? JsonConvert.DeserializeObject<Thingy>(await resp.Content.ReadAsStringAsync()) : null;
}
}
catch (Exception e)
{
return null;
}
}
I'm not adding the same object every loop iteration or anything silly like that and the request isn't returning nulls every time so I'm at a loss - my guess is this is some weird threading-related issue stemming from using async on mobile, or some undocumented incompatibility between HttpClient and Xamarin, but I don't really know where to go from here debugging-wise.
Because you only ever call list.Add() there is no way the list can be emptying itself. Therefore you must be looking a different list.
The function must be being called more than once, creating a new list each time. When debugging it is not always obvious that you are at a different list on a different thread.
As an afterthought: Something which might help you detect this kind of issue in the future is to turn on "Show threads in source".
Then, when debugging you will see these icons on the left, hinting that there is a second thread currently waiting at that line of code.
Although, personally I find them a bit unclear.

Check for internet connectivity from Unity

I have a Unity project which I build for Android and iOS platforms. I want to check for internet connectivity on Desktop, Android, and iOS devices. I've read about three different solutions:
Ping something (for example Google) - I totally dislike such decision, and I've read about mistakes on Android.
Application.internetReachability - According to Unity's documentation, this function will only determine that I have a POSSIBILITY of connecting to the Internet (it doesn't guarantee a real connection).
Network.TestConnection() - If I have no Internet connection, my application fails. So this isn't correct either.
How can I determine whether I have internet connectivity from within Unity?
I don't actually believe that Network.TestConnection() is the right tool for this job. According to the documentation, it looks to me like it's meant for testing if NAT is working and your client is publicly reachable by IP, but what you want to check for is whether you have general internet connectivity.
Here is a solution that I found on Unity Answers by user pixel_fiend, which simply tests a website to see if the user has connectivity. One benefit of this code is that it uses IEnumerator for asynchronous operation, so the connectivity test won't hold up the rest of your application:
IEnumerator checkInternetConnection(Action<bool> action){
WWW www = new WWW("http://google.com");
yield return www;
if (www.error != null) {
action (false);
} else {
action (true);
}
}
void Start(){
StartCoroutine(checkInternetConnection((isConnected)=>{
// handle connection status here
}));
}
You can change the website to whatever you want, or even modify the code to return success if any one of a number of sites are reachable. AFAIK there is no way to check for true internet connectivity without trying to connect to a specific site on the internet, so "pinging" one or more websites like this is likely to be your best bet at determining connectivity.
public static IEnumerator CheckInternetConnection(Action<bool> syncResult)
{
const string echoServer = "http://google.com";
bool result;
using (var request = UnityWebRequest.Head(echoServer))
{
request.timeout = 5;
yield return request.SendWebRequest();
result = !request.isNetworkError && !request.isHttpError && request.responseCode == 200;
}
syncResult(result);
}
void Start()
{
StartCoroutine(CheckInternetConnection(isConnected =>
{
if (isConnected)
{
Debug.Log("Internet Available!");
}
else
{
Debug.Log("Internet Not Available");
}
}));
}
IEnumerator CheckInternetConnection(Action<bool> action)
{
UnityWebRequest request = new UnityWebRequest("http://google.com");
yield return request.SendWebRequest();
if (request.error != null) {
Debug.Log ("Error");
action (false);
} else{
Debug.Log ("Success");
action (true);
}
}
Since WWW has deprecated, UnityWebRequest can be used instead.
i know this is old, but maybe can help you.
public bool CheckInternetConnection(){
return !(Application.internetReachability == NetworkReachability.NotReachable)
}
Ping 8.8.8.8 instead of sending a GET
unity already provides the tool for that:
Ping
The ping operation is asynchronous and a ping object can be polled for
status using Ping.isDone. When a response is received it is in
Ping.time.
Windows Store Apps: A stream socket is used to mimic ping
functionality, it will try to open a connection to specified IP
address using port 80. For this to work correctly, InternetClient
capability must be enabled in Package.appxmanifest.
Android: ICMP sockets are used for ping operation if they're
available, otherwise Unity spawns a child process /system/bin/ping for
ping operations. To check if ICMP sockets are available, you need to
read the contents for /proc/sys/net/ipv4/ping_group_range. If ICMP
sockets are available, this file should contain an entry for 0
2147483647.
using UnityEngine;
using System.Collections.Generic;
public class PingExample : MonoBehaviour
{
bool isConnected = false;
private IEnumerator Start()
{
while(true)
{
var ping = new Ping("8.8.8.8");
yield return new WaitForSeconds(1f);
while (!ping.isDone)
{
isConnected = false;
yield return null;
}
isConnected = true;
Debug.Log(ping.time);
}
}
}
I've created an Android's library that can be used as Unity's plugin for this purpose. If anyone's interested it's available under https://github.com/rixment/awu-plugin
As for the iOS version unfortunately I don't have enough of knowledge in this area. It would be nice if someone could extend the repo to include the iOS version too.
With the latest version of Unity, WWW has become obsolete, hence you need to use WebRequest.
This is the bit of codes I'm using to check if the user is online:
private string HtmlLookUpResult_Content;
private char[] HtmlLookUpResult_Chars;
private StreamReader HtmlLookUpResult_Reader;
private bool HtmlLookUpResult_isSuccess;
private HttpWebRequest HtmlLookUpResult_Request;
private HttpWebResponse HtmlLookUpResult_Response;
public bool CheckIfOnline()
{
HtmlLookUpResult_Content = UniversalEnum.String_Empty;
HtmlLookUpResult_Request = (HttpWebRequest)WebRequest.Create(UniversalEnum.WebHtml_isOnline);
HtmlLookUpResult_Request.Timeout = 5000;
try
{
using (HtmlLookUpResult_Response = (HttpWebResponse)HtmlLookUpResult_Request.GetResponse())
{
HtmlLookUpResult_isSuccess = (int)HtmlLookUpResult_Response.StatusCode < 299 && (int)HtmlLookUpResult_Response.StatusCode >= 200;
if (HtmlLookUpResult_isSuccess)
{
using (HtmlLookUpResult_Reader = new StreamReader(HtmlLookUpResult_Response.GetResponseStream()))
{
HtmlLookUpResult_Chars = new char[1];
HtmlLookUpResult_Reader.Read(HtmlLookUpResult_Chars, 0, 1);
HtmlLookUpResult_Content += HtmlLookUpResult_Chars[0];
}
}
}
}
catch
{
HtmlLookUpResult_Content = UniversalEnum.String_Empty;
}
if (HtmlLookUpResult_Content != UniversalEnum.String_Empty)
{
return true;
}
else
{
return false;
}
}
If you would like to know if the user is just online, you can get the result just from the boolean HtmlLookUpResult_isSuccess in the code. But, in reality, you most likely want to confirm the user has also access to your server or whatever remote system you use in your project, right? Which is what the remaining of the code does.
In case you wonder what UniversalEnum is, in my code, it's a separate non-Monobehavior script that contains all persistent variables (like strings and hashes) I'm planning on reusing in my project. For short:
UniversalEnum.String_Empty = "";
UniversalEnum.WebHtml_isOnline = "http://www.ENTER_YOUR_WEBSITE_HERE.com/games-latestnews/isOnline.html"
That isOnline.html file is, as you can see, a file in the folder "games-latestnews" in the HTML_content of my hosted website and it contains only [1] as it content. It has no header, no actual content and is pretty much like a .txt file set online. I'm using this method also because I can add new news to my game by just adding new HTML page in that folder. I'm also surrounding the content check with a Try{} so that if ANYTHING fails, it returns the Catch{} value and then by comparing if the content (a string) is an empty string or contain anything, we know if the user is both online and if he/she has access to your website.
On good example of why you would want to check that the user has both access to the net AND to your website is if the user is using a limited network such as what you might find at a school. If a school decided to ban your website due to whatever reason, just looking up if the connection is possible will return a false positive since it wouldn't access the actual webpage anyway.
You can check network connection using this code
if(Application.internetReachability == NetworkReachability.NotReachable){
Debug.Log("Error. Check internet connection!");
}

My timer loop intermittently slows down, not sure why

I have a API request queue that I have looped using System.Timers.Timer. I set it up like this:
private static void SetupTimerLoop()
{
queueLoopTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
queueLoopTimer.Interval = 100;
queueLoopTimer.Start();
}
Periodically OnTimedEvent will only get called once every second, almost exactly for large spans of time. It will then speed back up to once every 100ms. I cannot accurately reproduce these results, sometimes it happens, sometimes it does not. I have watched my CPU usage and it doesn't spike during these times of slowdown, if anything it goes down.
If I make breakpoints it shows that the timers interval is still only 100ms.
What could be going on here? Is there anything I can do to further troubleshoot this?
Potentially related, when this happens all my HTTP requests that are initiated from the loop (these are put onto Tasks so they return asynchronously) stop returning.
Request related:
private T Get<T>(string endpoint, IRequest request) where T : class
{
var client = InitHttpClient();
string debug = BaseUrl + endpoint + ToQueryString(request);
HttpResponseMessage response = client.GetAsync(BaseUrl + endpoint + ToQueryString(request)).Result;
string body = response.Content.ReadAsStringAsync().Result;
if (response.IsSuccessStatusCode)
{
T result = JsonConvert.DeserializeObject<T>(body, _serializerSettings);
return result;
}
var error = JsonConvert.DeserializeObject<HelpScoutError>(body);
throw new HelpScoutApiException(error, body);
}
I never get to: string body = response.Content.ReadAsStringAsync().Result; as long as the loop seems to be running slow.
Not sure if that could have something to do with it, hopefully you guys have some insight.
Edit: I don't flood the API with requests. I throttle the number of requests that go out per rolling 60-second period. During that time I just use an if statement to pass over the API call for that loop.
First of all, I'm not too clear when you say you have a loop. Your "OnTimedEvent" is an event handler that gets triggered at a preset interval (100ms).
As for a hint, you might want to try adding logic at the beginning of your "OnTimedEvent" handler to prevent re-entrance, just in-case your "OnTimedEvent" handler is taking longer than 100ms.
static int working = 0;
private static void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
{
if (working > 0)
return;
working++;
//do your normal work here
working--;
}

Stack overflow error in console application

I currently have a console application written in C# for production server environment. It's quite simple, but I've been testing it for +- 3 months now on my own server (semi-production, but not a disaster if the program fails). I've been getting stack overflow errors every few weeks or so, though.
Of course, pasting my entire source code here would be quite a long piece, so I will try to explain it the best I can: the program is in an infinite while loop (this is probably the cause of the issue), and it checks every second a few small things and prints to the console every so often (if no activity, every 15min, otherwise up-to every second).
Now why and how can I fix the stack overflow errors? Being able to run it for a couple weeks without issue may seem like a lot, but it is obviously not in a server production environment. My guess is that it's the fact I'm using a while loop, but what alternatives do I have?
Edit: here's a portion of the code:
int timeLoop = 0;
while (true)
{
// If it has been +-10min since last read of messages file, read again
if (timeLoop > 599)
{
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss") + " Reading messages...");
messagesFile = File.ReadAllText(#"messages.cfg");
messages = messagesFile.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
timeLoop = 0;
}
// For each message, check if time specified equals current time, if so say message globally.
foreach (string x in messages)
{
string[] messageThis = x.Split('~');
int typeLoop = 0;
if (messageThis[2] != "no-loop")
typeLoop = Convert.ToInt16(messageThis[2].Remove(0, 5));
DateTime checkDateTime = DateTime.ParseExact(messageThis[0], "HH:mm:ss", null);
if (typeLoop == 0)
{
if (checkDateTime.ToString("HH:mm:ss") == DateTime.Now.ToString("HH:mm:ss"))
publicMethods.sayGlobal(messageThis[1]);
}
else
{
DateTime originalDateTime = checkDateTime;
do
{
checkDateTime = checkDateTime.AddHours(typeLoop);
if (checkDateTime.ToString("HH:mm:ss") == DateTime.Now.ToString("HH:mm:ss"))
publicMethods.sayGlobal(messageThis[1]);
} while (checkDateTime.ToString("HH:mm:ss") != originalDateTime.ToString("HH:mm:ss"));
}
}
timeLoop++;
Thread.Sleep(1000);
}
Also, I forgot that I actually have this code on Github, which probably helps a lot. I know you shouldn't be using any links to code and have them here, so that's why I included the snippet above - but if you are interested in helping me out the repository is located here. Another note - I know that doing it like this is not very accurate on timing - but this is not much of an issue at the moment.
BattleEyeClient.Connect can call itself in some (failing) circumstances, and this method can be called by sayGlobal - so you probably want to change this code block (from line 98):
catch
{
if (disconnectionType == BattlEyeDisconnectionType.ConnectionLost)
{
Disconnect(BattlEyeDisconnectionType.ConnectionLost);
Connect();
return BattlEyeConnectionResult.ConnectionFailed;
}
else
{
OnConnect(loginCredentials, BattlEyeConnectionResult.ConnectionFailed);
return BattlEyeConnectionResult.ConnectionFailed;
}
}
Maybe keep track of how many reconnection attempts you make or transform this section of code so that it is a while loop rather than a recursive call during this failure mode.
Even worse, of course, is if that recursive Connect call succeeds, this catch block then returns BattlEyeConnectionResult.ConnectionFailed which it probably shouldn't.

C# application problem in Release build only

the problem only appears when making Release build and running exe file ( not from visual studio )
in all other combination either it's running from visual studio or running exe everything works fine
I'm running Function Load using backgroundWorker
Load:
while (!Request.GAMELIST.XMLReceived) ;
GameEngine.ParseGameList( Request.GAMELIST.XML );
Request.GAMELIST.XMLReceived = false;
while loop in this fragment works like delay
it should wait till XML is received from server and then continue
but it stucks in above specified situation
if I'll put MessageBox.show("here we go"); after while loop
messageBox will not appear
but if I'll put MessageBox.show("here we go"); before while loop
application will receive data until I click messagebox ok
and then everything will work fine
here is GAMELIST class implementation
public class RequestGAMELIST
{
public string XML;
public bool XMLReceived = false;
public void ParseRequest( string request )
{
int index = request.IndexOf(':') + 2;
XML = request.Substring(index, request.Length - index);
XMLReceived = true;
}
}
please provide help if you can
this is really strange thing which I can't figure out by my self
Thanks.
Yes, this code has very good odds to hang in the Release build. The JIT optimizer doesn't know that the variable might be set to true by code outside of the method. You need to tell it that, like this:
public class RequestGAMELIST
{
public volatile bool XMLReceived = false;
// etc..
}
The volatile keyword ensures that the jitter won't store the variable value in a CPU register.
That solves your problem, it is still not the right way to do it. You should use an AutoResetEvent instead. It ensures that the thread responds to the variable change is quickly as possible. And most importantly, it lets the thread block so it doesn't burn any cpu cycles.
public class RequestGAMELIST
{
public AutoResetEvent XMLReceived = new AutoResetEvent();
public void ParseRequest( string request )
{
int index = request.IndexOf(':') + 2;
XML = request.Substring(index, request.Length - index);
XMLReceived.Set();
}
}
In your thread:
XMLReceived.WaitOne();
GameEngine.ParseGameList( Request.GAMELIST.XML );
This is a bad idea:
while (!Request.GAMELIST.XMLReceived) ;
At least you should be doing something like:
while (!Request.GAMELIST.XMLReceived) {
System.Threading.Thread.Sleep(100); // Don't hog the CPU!
}
Your program runs fine in debug mode perhaps due to certain debug routines added inside the while loop which makes it run slower...

Categories

Resources