I wrote a Windows service using an HttpListener
to process the requests from points asynchronously.
It works fine, but sometimes it runs into a problem that requires restarting the service or server to fix. Initially I declared the listener object with:
public HttpListener PointsListener = new HttpListener();
Here is the code of the method, where I starting listening. I'm calling it from the OnStart
method of the service:
public string ListenerStart()
{
try
{
if (!PointsListener.IsListening)
{
PointsListener.Prefixes.Add(String.Concat("http://*:", points_port, "/"));
PointsListener.Start();
Point开发者_开发知识库sListener.BeginGetContext(PointProcessRequest, PointsListener);
LogWriter("Http listener activated on port " + points_port);
return "Listener started";
}
else
{
return "Listener is already started!";
}
}
catch (Exception err)
{
LogWriter("Error in LIstenerStart \r\n" + err.ToString());
return ("Error: " + err.Message);
}
}
Here are the methods which process requests:
private void PointProcessRequest(IAsyncResult result)
{
HttpListener listener = (HttpListener)result.AsyncState;
HttpListenerContext context = listener.EndGetContext(result);
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
response.KeepAlive = false;
System.IO.Stream output = response.OutputStream;
try
{
//declaring a variable for responce
string responseString = "<html>My Response: request is not allowed by server protocol</html>";
// Commands and actions to set responceString
byte[] buffer = Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
output.Write(buffer, 0, buffer.Length);
}
catch (Exception err)
{
LogWriter("Error in PointProcessRequest: \r\n" + err.ToString());
}
finally
{
try
{
output.Flush();
output.Close();
response.Close();
}
catch (Exception err)
{
LogWriter("Error in PointProcessRequest CLOSING OUTPUT STREAM: \r\n" + err.ToString());
}
finally
{
PointsListener.BeginGetContext(PointProcessRequest, PointsListener);
}
}
}
It is working well some of the time, but the following error appears in the log:
Error in PointProcessRequest:
System.Net.HttpListenerException: The specified network name is no longer available
в System.Net.HttpResponseStream.Write(Byte[] buffer, Int32 offset, Int32 size)
в ARK_Dealer.ark.PointProcessRequest(IAsyncResult result)
[26.01.2011 9:00:54] Error in PointProcessRequest CLOSING OUTPUT STREAM:
System.InvalidOperationException: Cannot close stream until all bytes are written.
в System.Net.HttpResponseStream.Dispose(Boolean disposing)
в System.IO.Stream.Close()
в ARK_Dealer.ark.PointProcessRequest(IAsyncResult result)
I think that problem appears when some point sends the request to server but before the receiving answer looses the connection.
How can I prevent the exception from being thrown? Will be the response object be properly disposed of automatically? How can I solve the problem?
I'm using a HttpListener in production and I've found the nicest way to resolve this issue, without adding a whole bunch of try/catch blocks which do nothing to communicate the logic of the code at hand; is to quite simply to set Listener.IgnoreWriteExceptions = true;
and, voilà no more write exceptions!
There is a related question about this.
What you are doing is fine, since there is nothing else that can be done about the other side closing the connection or the connection being dropped. You might want to catch the exact exception and call output.Dispose()
and other cleanup or simply let the finalizers handle the release if it doesn't happen very often.
I had the same problem recently, and solved it by wrapping the output in a try/catch:
try
{
byte[] buffer = Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
output.Write(buffer, 0, buffer.Length);
}
catch (HttpListenerException)
{
// Handle error caused by connection being lost
}
Problem solved!!! I just removed this:
finally
{
PointsListener.BeginGetContext(PointProcessRequest, PointsListener);
}
and inserted this command at the begin of PointProcessRequest method!
IAsyncResult _result = listener.BeginGetContext(new AsyncCallback(PointProcessRequest), listener);
Problem solved at 100%!!!
精彩评论