异步检索请求时,C#HTTP侦听器ObjectDisposedException

时间:2019-04-08 08:43:37

标签: c# asynchronous server httplistener

我是一个初学者,所以请多多包涵。

我一直在尝试编写一个非常简单的C#HTTP侦听器,它可以异步处理客户端请求。

为此,我使用了来自官方Microsoft文档的以下示例代码:

https://docs.microsoft.com/de-de/dotnet/api/system.net.httplistener.begingetcontext?view=netframework-4.7.2

即使我使用的是完全相同的代码,我仍会收到ObjectDisposed异常。我只能通过在主线程中手动等待几毫秒来修复它,但这是我要修复的一个糟糕的解决方案,因为它显然会极大地降低所有速度。

似乎主线程根本不等待并在完成工作之前关闭侦听器,从而导致对象被过早处置。我想这就是为什么手动等待修复它的原因。但是,为什么WaitOne()方法不等待?

为减少人为错误,我使代码几乎与示例相同,我仅手动添加了前缀。

听众:

public static void NonblockingListener()
{
    HttpListener listener = new HttpListener();
    listener.Prefixes.Add("http://localhost:8080/test/");
    listener.Start();

    IAsyncResult result = listener.BeginGetContext(new AsyncCallback(ListenerCallback),listener);

    Console.WriteLine("Waiting for request to be processed asyncronously.");
    result.AsyncWaitHandle.WaitOne();
    Console.WriteLine("Request processed asyncronously.");

    // It will only work if I add this: System.Threading.Thread.Sleep(200);
    listener.Close();
}

回调方法:

public static void ListenerCallback(IAsyncResult result)
{
    HttpListener listener = (HttpListener) result.AsyncState;  

    // It throws the exception at this line
    HttpListenerContext context = listener.EndGetContext(result);

    HttpListenerRequest request = context.Request;
    HttpListenerResponse response = context.Response;

    string responseString = "<HTML><BODY> Hello world!</BODY></HTML>";
    byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
    response.ContentLength64 = buffer.Length;
    System.IO.Stream output = response.OutputStream;
    output.Write(buffer,0,buffer.Length);
    output.Close();
}

最后,这就是我设置主要功能的方式,它只是一个简单的无限循环:

static void Main(string[] args)
{
     while (true)
         NonblockingListener();
}

我是愚蠢的还是假设示例代码有问题是正确的? 那会很奇怪,但是我真的不知道我在做什么错。

如果有人可以复制相同的示例代码并尝试运行它,那就太好了。

要使其按预期工作,我需要更改什么?

1 个答案:

答案 0 :(得分:0)

I figured it out myself after some more painful hours, I'll just post an answer here anyway in case someone has the same problem. The problem was that I kept closing and recreating the Listener instead of reusing it for the next request. This is a mistake I copied from the MSDN sample code page. It closes the Listener immediately after retrieving a client request, resulting in an error because the callback method can't access the closed Listener anymore to deal with the still running request.

The solution is to remove the loop in the main function and instead put an infinite loop around:

IAsyncResult result = listener.BeginGetContext(newAsyncCallback(ListenerCallback),listener);
result.AsyncWaitHandle.WaitOne();

It seems obvious like that, but I guess I just took the MSDN for granted, which apparently is a mistake.