I have an ASP.NET 3.5 app using WebForms, currently it is being hosted on IIS6. Everything behaves great.
However, after switching to a Windows 2012 server with IIS8 installed, we intermittently get truncated requests. The majority of the time this manifests in a viewstate exception in our event log, however, on forms that do not have ViewState, we get incomplete posts (the last few fields are missing / partially truncated).
This became so problematic that we escalated to Microsoft support, and after weeks of debugging, they said that this is the "correct" behavior for II7 and above. Their explanation was the change in the IIS pipeline from 6 to 7.
IIS6 and below would buffer the entire request before passing it along to Asp.net, truncated requests would be ignored.
IIS7 and above would send the request to Asp.net after the initial headers were sent, it would be up to the app to handle truncated requests.
This becomes problematic when either there are connectivity issues (the user unplugs their cable during tranmission) or when the user presses stop / reloads the page during a post.
In our HTTP logs, we see "connection_dropped" messages that correlate to the truncated requests.
I am having trouble believing that this behavior is intended, but we have tested on a few different servers and get the same results with IIS7 and above (Windows 2008, 2008 R2, and 2012).
My questions are:
1) Does this behavior even make sense?
2) If this is "correct" behavior, how do you protect your app against potentially processing incomplete data?
3) Why is it the application developer's responsibility to detect incomplete requests? Hypothetically, why would the app developer handle the incomplete request other than ignoring it?
Update
I wrote a small asp.net application and website to demonstrate the issue.
Server
Handler.ashx.cs
public class Handler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.Request.HttpMethod == "POST")
{
var lengthString = context.Request.Form["Length"];
var data = context.Request.Form["Data"];
if (lengthString == null)
{
throw new Exception("Missing field: Length");
}
if (data == null)
{
throw new Exception("Missing field: Data");
}
var expectedLength = int.Parse(lengthString);
if (data.Length != expectedLength)
{
throw new Exception(string.Format("Length expected: {0}, actual: {1}, difference: {2}", expectedLength, data.Length, expectedLength - data.Length));
}
}
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World, Request.HttpMethod=" + context.Request.HttpMethod);
}
public bool IsReusable
{
get { return false; }
}
}
Client
Program.cs
static void Main(string[] args)
{
var uri = new Uri("http://localhost/TestSite/Handler.ashx");
var data = new string('a', 1024*1024); // 1mb
var payload = Encoding.UTF8.GetBytes(string.Format("Length={0}&Data={1}", data.length, data));
// send request truncated by 256 bytes
// my assumption here is that the Handler.ashx should not try and handle such a request
Post(uri, payload, 256);
}
private static void Post(Uri uri, byte[] payload, int bytesToTruncate)
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
// this allows us to disconnect unexpectedly
LingerState = new LingerOption(true, 0)
};
socket.Connect(uri.Host, uri.Port);
SendRequest(socket, uri, payload, bytesToTruncate);
socket.Close();
}
private static void SendRequest(Socket socket, Uri uri, byte[] payload, int bytesToTruncate)
{
var headers = CreateHeaders(uri, payload.Length);
SendHeaders(socket, headers);
SendBody(socket, payload, Math.Max(payload.Length - bytesToTruncate, 0));
}
private static string CreateHeaders(Uri uri, int contentLength)
{
var headers = new StringBuilder();
headers.AppendLine(string.Format("POST {0} HTTP/1.1", uri.PathAndQuery));
headers.AppendLine(string.Format("Host: {0}", uri.Host));
headers.AppendLine("Content-Type: application/x-www-form-urlencoded");
headers.AppendLine("User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/99.0");
headers.AppendLine("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
headers.AppendLine("Connection: Close");
headers.AppendLine(string.Format("Content-Length: {0}", contentLength));
return headers.ToString();
}
private static void SendHeaders(Socket socket, string headers)
{
socket.Send(Encoding.ASCII.GetBytes(headers));
socket.Send(Encoding.ASCII.GetBytes("\n"));
}
private static void SendBody(Socket socket, byte[] payload, int numBytesToSend)
{
socket.Send(payload, 0, numBytesToSend, SocketFlags.None);
}
1) If you're running pipeline for the app pool to which your 3.5 application is assigned in Integrated mode, you might have trouble with how your requests are handled due to ISAPI behavior. You may be generating requests it doesn't understand properly and it then truncates them to a default value. Have you tried running the app pool in Classic mode?
2) Functional testing. Lots and lots of functional testing. Create a test harness and make all the calls your application can make to make sure it's working properly. This is not a 100% solution, but nothing really is. There are many computer science papers explaining why it's impossible to test every single possible situation in which your app may run based on the Halting Problem.
3) Because you wrote the code. You should not have incomplete requests because the request might be for an important piece of data and you need to send back an error saying that there was a problem processing a request, otherwise the issuing party just sees the request as having mysteriously vanished.
The reason IIS changed its behaviour because we (developers) needed more control over request handling. In case of broken request, we had problem investigating cause of invisible requests. We need to log requests at application level for investigation & record keeping. For example, if request involves a financial transaction like credit card transaction, we need more control and we need to record every step for compliance.
IIS is a web server framework and application level data validation is not their responsibility. If request was broken, that means the input was incomplete & application level logic will decide what to do. Application must respond correct error codes and by failures. This is the reason ASP.NET mvc has model validation which allows you to validate complete input at application level.
You can use IsClientConnected to check whether the underlying socket is still connected or not.
As the web has gone more AJAX, and more mobile, and we sometimes use ping to check health of remote services, we do not necessarily conclude that broken request is an error and must be dropped. We may still want to live with broken requests. It is the choice that application level developer can make and not the IIS.
Related
In Unity3D, is there any way to instantly check network availability? By "instantly", I mean during a single frame, because lines of code below this check need to work based on network availability.
It all happens during Start(). I know I can ping a web page, and get network availability based on any errors occurring during the download of a web page. However, an operation like this takes several seconds whereas I need to know the result immediately, before moving to next line of code in the script.
Assuming your game is running at reasonable frame rates 30fps or greater then any solution that you can come up with (even pinging the host of your server) will only be valid for instances where the latency of the round trip is less than 1/30th of a second or lower ( roughly 30 ms)
As such it is unrealistic to handle this between frames (except for maybe on local networks)
Instead i would suggest into looking into threading your network based code to decouple it from frames
Don't do this.
As long as you do not provide more information of what exactly you are planning, one cannot give you proper answers.
This is unsatisfying for both sides.
But what you actually could do:
Open a TCP connection to a web available device like the google.com server.
Once the network state is changed (connected, disconnected, ...) trigger a simple c# event or set a variable like isOnline = true;.
This can be a way. But it is a bad one.
It all happens during Start()
Yes, this is possible and can be done in one frame if this is the case. I would have discouraged it so much if this operation is performed every frame in the Update function but that's not the case. If this is done in the beginning of the app, that's fine. If you do this while the game is running, you will affect the performace.
but operation like this take several seconds
This is designed like this in order to avoid blocking the main Thread.
Network operation should be done in a Thread or with the async methods to avoid blocking the main Thread. This is how most Unity network API such as the WWW and UnityWebRequest work. They use Thread in the background and then give you coroutine to manage that Thread by yielding/waiting in a coroutine function over frames until the network request completes.
To accomplish this in one frame just use HttpWebRequest and provide a server url to check. Most examples uses the google.com since that's always online but make sure to provide "User-Agent" so that the connection is not rejected on mobile devices. Finally, if HttpStatusCode is not 200 or if there is an exception then there is a problem, otherwise assume it is connected.
bool isOnline()
{
bool success = true;
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://google.com");
request.Method = "GET";
//Make sure Google don't reject you when called on mobile device (Android)
request.changeSysTemHeader("User-Agent", "Mozilla / 5.0(Windows NT 10.0; WOW64) AppleWebKit / 537.36(KHTML, like Gecko) Chrome / 55.0.2883.87 Safari / 537.36");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response == null)
{
success = false;
}
if (response != null && response.StatusCode != HttpStatusCode.OK)
{
success = false;
}
}
catch (Exception)
{
success = false;
}
return success;
}
Class for the custom changeSysTemHeader function used to change the User-Agent:
public static class ExtensionMethods
{
public static void changeSysTemHeader(this HttpWebRequest request, string key, string value)
{
WebHeaderCollection wHeader = new WebHeaderCollection();
wHeader[key] = value;
FieldInfo fildInfo = request.GetType().GetField("webHeaders",
System.Reflection.BindingFlags.NonPublic
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.GetField);
fildInfo.SetValue(request, wHeader);
}
}
Simple usage from the Start function done in one frame:
void Start()
{
Debug.Log(isOnline());
}
I want to extend my experience with the .NET framework and want to build a client/server application.
Actually, the client/server is a small Point Of Sale system but first, I want to focus on the communication between server and client.
In the future, I want to make it a WPF application but for now, I simply started with a console application.
2 functionalities:
client(s) receive(s) a dataset and every 15/30min an update with changed prices/new products
(So the code will be in a Async method with a Thread.sleep for 15/30 mins).
when closing the client application, sending a kind of a report (for example, an xml)
On the internet, I found lots of examples but i can't decide which one is the best/safest/performanced manner of working so i need some advice for which techniques i should implement.
CLIENT/SERVER
I want 1 server application that handles max 6 clients. I read that threads use a lot of mb and maybe a better way will be tasks with async/await functionallity.
Example with ASYNC/AWAIT
http://bsmadhu.wordpress.com/2012/09/29/simplify-asynchronous-programming-with-c-5-asyncawait/
Example with THREADS
mikeadev.net/2012/07/multi-threaded-tcp-server-in-csharp/
Example with SOCKETS
codereview.stackexchange.com/questions/5306/tcp-socket-server
This seems to be a great example of sockets, however, the revisioned code isn't working completely because not all the classes are included
msdn.microsoft.com/en-us/library/fx6588te(v=vs.110).aspx
This example of MSDN has a lot more with Buffersize and a signal for the end of a message. I don't know if this just an "old way" to do this because in my previous examples, they just send a string from the client to the server and that's it.
.NET FRAMEWORK REMOTING/ WCF
I found also something about the remoting part of .NET and WCF but don' know if I need to implement this because i think the example with Async/Await isn't bad.
SERIALIZED OBJECTS / DATASET / XML
What is the best way to send data between it? Juse an XML serializer or just binary?
Example with Dataset -> XML
stackoverflow.com/questions/8384014/convert-dataset-to-xml
Example with Remoting
akadia.com/services/dotnet_dataset_remoting.html
If I should use the Async/Await method, is it right to something like this in the serverapplication:
while(true)
{
string input = Console.ReadLine();
if(input == "products")
SendProductToClients(port);
if(input == "rapport")
{
string Example = Console.ReadLine();
}
}
Here are several things anyone writing a client/server application should consider:
Application layer packets may span multiple TCP packets.
Multiple application layer packets may be contained within a single TCP packet.
Encryption.
Authentication.
Lost and unresponsive clients.
Data serialization format.
Thread based or asynchronous socket readers.
Retrieving packets properly requires a wrapper protocol around your data. The protocol can be very simple. For example, it may be as simple as an integer that specifies the payload length. The snippet I have provided below was taken directly from the open source client/server application framework project DotNetOpenServer available on GitHub. Note this code is used by both the client and the server:
private byte[] buffer = new byte[8192];
private int payloadLength;
private int payloadPosition;
private MemoryStream packet = new MemoryStream();
private PacketReadTypes readState;
private Stream stream;
private void ReadCallback(IAsyncResult ar)
{
try
{
int available = stream.EndRead(ar);
int position = 0;
while (available > 0)
{
int lengthToRead;
if (readState == PacketReadTypes.Header)
{
lengthToRead = (int)packet.Position + available >= SessionLayerProtocol.HEADER_LENGTH ?
SessionLayerProtocol.HEADER_LENGTH - (int)packet.Position :
available;
packet.Write(buffer, position, lengthToRead);
position += lengthToRead;
available -= lengthToRead;
if (packet.Position >= SessionLayerProtocol.HEADER_LENGTH)
readState = PacketReadTypes.HeaderComplete;
}
if (readState == PacketReadTypes.HeaderComplete)
{
packet.Seek(0, SeekOrigin.Begin);
BinaryReader br = new BinaryReader(packet, Encoding.UTF8);
ushort protocolId = br.ReadUInt16();
if (protocolId != SessionLayerProtocol.PROTOCAL_IDENTIFIER)
throw new Exception(ErrorTypes.INVALID_PROTOCOL);
payloadLength = br.ReadInt32();
readState = PacketReadTypes.Payload;
}
if (readState == PacketReadTypes.Payload)
{
lengthToRead = available >= payloadLength - payloadPosition ?
payloadLength - payloadPosition :
available;
packet.Write(buffer, position, lengthToRead);
position += lengthToRead;
available -= lengthToRead;
payloadPosition += lengthToRead;
if (packet.Position >= SessionLayerProtocol.HEADER_LENGTH + payloadLength)
{
if (Logger.LogPackets)
Log(Level.Debug, "RECV: " + ToHexString(packet.ToArray(), 0, (int)packet.Length));
MemoryStream handlerMS = new MemoryStream(packet.ToArray());
handlerMS.Seek(SessionLayerProtocol.HEADER_LENGTH, SeekOrigin.Begin);
BinaryReader br = new BinaryReader(handlerMS, Encoding.UTF8);
if (!ThreadPool.QueueUserWorkItem(OnPacketReceivedThreadPoolCallback, br))
throw new Exception(ErrorTypes.NO_MORE_THREADS_AVAILABLE);
Reset();
}
}
}
stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(ReadCallback), null);
}
catch (ObjectDisposedException)
{
Close();
}
catch (Exception ex)
{
ConnectionLost(ex);
}
}
private void Reset()
{
readState = PacketReadTypes.Header;
packet = new MemoryStream();
payloadLength = 0;
payloadPosition = 0;
}
If you're transmitting point of sale information, it should be encrypted. I suggest TLS which is easily enabled on through .Net. The code is very simple and there are quite a few samples out there so for brevity I'm not going to show it here. If you are interested, you can find an example implementation in DotNetOpenServer.
All connections should be authenticated. There are many ways to accomplish this. I've use Windows Authentication (NTLM) as well as Basic. Although NTLM is powerful as well as automatic it is limited to specific platforms. Basic authentication simply passes a username and password after the socket has been encrypted. Basic authentication can still, however; authenticate the username/password combination against the local server or domain controller essentially impersonating NTLM. The latter method enables developers to easily create non-Windows client applications that run on iOS, Mac, Unix/Linux flavors as well as Java platforms (although some Java implementations support NTLM). Your server implementation should never allow application data to be transferred until after the session has been authenticated.
There are only a few things we can count on: taxes, networks failing and client applications hanging. It's just the nature of things. Your server should implement a method to clean up both lost and hung client sessions. I've accomplished this in many client/server frameworks through a keep-alive (AKA heartbeat) protocol. On the server side I implement a timer that is reset every time a client sends a packet, any packet. If the server doesn't receive a packet within the timeout, the session is closed. The keep-alive protocol is used to send packets when other application layer protocols are idle. Since your application only sends XML once every 15 minutes sending a keep-alive packet once a minute would able the server side to issue an alert to the administrator when a connection is lost prior to the 15 minute interval possibly enabling the IT department to resolve a network issue in a more timely fashion.
Next, data format. In your case XML is great. XML enables you to change up the payload however you want whenever you want. If you really need speed, then binary will always trump the bloated nature of string represented data.
Finally, as #NSFW already stated, threads or asynchronous doesn't really matter in your case. I've written servers that scale to 10000 connections based on threads as well as asynchronous callbacks. It's all really the same thing when it comes down to it. As #NSFW said, most of us are using asynchronous callbacks now and the latest server implementation I've written follows that model as well.
Threads are not terribly expensive, considering the amount of RAM available on modern systems, so I don't think it's helpful to optimize for a low thread count. Especially if we're talking about a difference between 1 thread and 2-5 threads. (With hundreds or thousands of threads, the cost of a thread starts to matter.)
But you do want to optimize for minimal blocking of whatever threads you do have. So for example instead of using Thread.Sleep to do work on 15 minute intervals, just set a timer, let the thread return, and trust the system to invoke your code 15 minutes later. And instead of blocking operations for reading or writing information over the network, use non-blocking operations.
The async/await pattern is the new hotness for asynchronous programming on .Net, and it is a big improvement over the Begin/End pattern that dates back to .Net 1.0. Code written with async/await is still using threads, it is just using features of C# and .Net to hide a lot of the complexity of threads from you - and for the most part, it hides the stuff that should be hidden, so that you can focus your attention on your application's features rather than the details of multi-threaded programming.
So my advice is to use the async/await approach for all of your IO (network and disk) and use timers for periodic chores like sending those updates you mentioned.
And about serialization...
One of the biggest advantages of XML over binary formats is that you can save your XML transmissions to disk and open them up using readily-available tools to confirm that the payload really contains the data that you thought would be in there. So I tend to avoid binary formats unless bandwidth is scarce - and even then, it's useful to develop most of the app using a text-friendly format like XML, and then switch to binary after the basic mechanism of sending and receiving data have been fleshed out.
So my vote is for XML.
And regarding your code example, well ther's no async/await in it...
But first, note that a typical simple TCP server will have a small loop that listens for incoming connections and starts a thread to hanadle each new connection. The code for the connection thread will then listen for incoming data, process it, and send an appropriate response. So the listen-for-new-connections code and the handle-a-single-connection code are completely separate.
So anyway, the connection thread code might look similar to what you wrote, but instead of just calling ReadLine you'd do something like "string line = await ReadLine();" The await keyword is approximately where your code lets one thread exit (after invoking ReadLine) and then resumes on another thread (when the result of ReadLine is available). Except that awaitable methods should have a name that ends with Async, for example ReadLineAsync. Reading a line of text from the network is not a bad idea, but you'll have to write ReadLineAsync yourself, building upon the existing network API.
I hope this helps.
I'm using 2 WebClients in my app, for 2 different weather API's.
When my internet connection is slow I get an exception from one of the API's.. It returns a 404 Notfound error.
I have tested this by disabling my WiFi, and put the data connection to '2G'. The first API returns the data with no problem, the second API however crashes my app with a WebException.
When I turn on the WiFi again it works flawlessly. Looks like the second API has a very little patience with slow connections.
Is there a way to fix this? I have also tried to change the WebClient into a HttpWebRequest but the problem still occurs.
Kind regards,
Niels
EDIT
My code:
private void GettingTheData()
{
WebClient Client = new WebClient();
Client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Client _DownloadStringCompleted);
Client.DownloadStringAsync(new Uri("http://theURI.com"));
}
void Client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
string result = e.Result.ToString();
// Let's do the cool stuff overhere
}
There exist HTTP Client library for WP which contains support for timeout. Article about it.
Some sample code for Windows Phone 8:
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
var httpClient = new HttpClient {Timeout = TimeSpan.FromSeconds(30)};
var responseBodyAsText = await httpClient.GetStringAsync("www.contoso.com");
}
Maybe the problem isn't the network latency. Perhaps your second API has a requirement that callers send a user-agent string, or some other HTTP header that you aren't sending. The fact that it works over WiFi and not 2G could have something to do with the fact that any device connecting from your WiFi network would appear to be the same to the server hosting the API (from an IP Address standpoint) and may allow access based on some cached identity (maybe you browsed the service to test it from your development PC). I would be interested to see what would happen if you connected to a different WiFi network if the response would be similar.
My immediate suggestion would be to catch the WebException and give the user a chance to retry.
I would have added this as a comment but I guess I don't have enough reputation for that.
Try increasing the ServicePointManager.DefaultConnectionLimit though the default is 2.
I need to create an C# application that will monitor whether a set of web services are up and running. User will select a service name from a dropdown. The program need to test with the corresponding service URL and show whether the service is running. What is the best way to do it? One way I am thinking of is to test whether we are able to download the wsdl. IS there a better way?
Note: The purpose of this application is that the user need to know only the service name. He need not remember/store the corresponding URL of the service.
I need a website version and a desktop application version of this C# application.
Note: Existing services are using WCF. But in future a non-WCF service may get added.
Note: My program will not be aware of (or not interested in ) operations in the service. So I cannot call a service operation.
REFERENCE
How to check if a web service is up and running without using ping?
C program-How do I check if a web service is running
this would not guarantee functionality, but at least you could check connectivity to a URL:
var url = "http://url.to.che.ck/serviceEndpoint.svc";
try
{
var myRequest = (HttpWebRequest)WebRequest.Create(url);
var response = (HttpWebResponse)myRequest.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
// it's at least in some way responsive
// but may be internally broken
// as you could find out if you called one of the methods for real
Debug.Write(string.Format("{0} Available", url));
}
else
{
// well, at least it returned...
Debug.Write(string.Format("{0} Returned, but with status: {1}",
url, response.StatusDescription));
}
}
catch (Exception ex)
{
// not available at all, for some reason
Debug.Write(string.Format("{0} unavailable: {1}", url, ex.Message));
}
This approach works for me.
I used Socket to check if the process can connect.
HttpWebRequest works if you try to check the connection 1-3 times but if you have a process which will run 24hours and from time to time needs to check the webserver availability that will not work anymore because will throw TimeOut Exception.
Socket socket
= new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var result = socket.BeginConnect("xxx.com", 80, null, null);
// test the connection for 3 seconds
bool success = result.AsyncWaitHandle.WaitOne(3000,false);
var resturnVal = socket.Connected;
if (socket.Connected)
socket.Disconnect(true);
socket.Dispose();
return resturnVal;
Given an async controller:
public class MyController : AsyncController
{
[NoAsyncTimeout]
public void MyActionAsync() { ... }
public void MyActionCompleted() { ... }
}
Assume MyActionAsync kicks off a process that takes several minutes. If the user now goes to the MyAction action, the browser will wait with the connection open. If the user closes his browser, the connection is closed. Is it possible to detect when that happens on the server (preferably inside the controller)? If so, how? I've tried overriding OnException but that never fires in this scenario.
Note: I do appreciate the helpful answers below, but the key aspect of this question is that I'm using an AsyncController. This means that the HTTP requests are still open (they are long-lived like COMET or BOSH) which means it's a live socket connection. Why can't the server be notified when this live connection is terminated (i.e. "connection reset by peer", the TCP RST packet)?
I realise this question is old, but it turned up frequently in my search for the same answer.
The details below only apply to .Net 4.5
HttpContext.Response.ClientDisconnectedToken is what you want. That will give you a CancellationToken you can pass to your async/await calls.
public async Task<ActionResult> Index()
{
//The Connected Client 'manages' this token.
//HttpContext.Response.ClientDisconnectedToken.IsCancellationRequested will be set to true if the client disconnects
try
{
using (var client = new System.Net.Http.HttpClient())
{
var url = "http://google.com";
var html = await client.GetAsync(url, HttpContext.Response.ClientDisconnectedToken);
}
}
catch (TaskCanceledException e)
{
//The Client has gone
//you can handle this and the request will keep on being processed, but no one is there to see the resonse
}
return View();
}
You can test the snippet above by putting a breakpoint at the start of the function then closing your browser window.
And another snippet, not directly related to your question but useful all the same...
You can also put a hard limit on the amount of time an action can execute for by using the AsyncTimeout attribute. To use this use add an additional parameter of type CancellationToken. This token will allow ASP.Net to time-out the request if execution takes too long.
[AsyncTimeout(500)] //500ms
public async Task<ActionResult> Index(CancellationToken cancel)
{
//ASP.Net manages the cancel token.
//cancel.IsCancellationRequested will be set to true after 500ms
try
{
using (var client = new System.Net.Http.HttpClient())
{
var url = "http://google.com";
var html = await client.GetAsync(url, cancel);
}
}
catch (TaskCanceledException e)
{
//ASP.Net has killed the request
//Yellow Screen Of Death with System.TimeoutException
//the return View() below wont render
}
return View();
}
You can test this one by putting a breakpoint at the start of the function (thus making the request take more than 500ms when the breakpoint is hit) then letting it run out.
Does not Response.IsClientConnected work fairly well for this? I have just now tried out to in my case cancel large file uploads. By that I mean if a client abort their (in my case Ajax) requests I can see that in my Action. I am not saying it is 100% accurate but my small scale testing shows that the client browser aborts the request, and that the Action gets the correct response from IsClientConnected.
It's just as #Darin says. HTTP is a stateless protocol which means that there are no way (by using HTTP) to detect if the client is still there or not. HTTP 1.0 closes the socket after each request, while HTTP/1.1 can keep it open for a while (a keep alive timeout can be set as a header). That a HTTP/1.1 client closes the socket (or the server for that matter) doesn't mean that the client has gone away, just that the socket hasn't been used for a while.
There are something called COMET servers which are used to let client/server continue to "chat" over HTTP. Search for comet here at SO or on the net, there are several implementations available.
For obvious reasons the server cannot be notified that the client has closed his browser. Or that he went to the toilet :-) What you could do is have the client continuously poll the server with AJAX requests at regular interval (window.setInterval) and if the server detects that it is no longer polled it means the client is no longer there.