Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# problem with HttpListener

Tags:

c#

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();
                PointsListener.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?

like image 599
Khisrav Avatar asked Jan 26 '11 06:01

Khisrav


3 Answers

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!

like image 189
Josh Avatar answered Sep 28 '22 17:09

Josh


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.

like image 30
Amir Avatar answered Sep 28 '22 19:09

Amir


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
}
like image 41
Jim Mischel Avatar answered Sep 28 '22 17:09

Jim Mischel