C# 第二次调用HttpClient';s PostAsJsonAsync stucks

C# 第二次调用HttpClient';s PostAsJsonAsync stucks,c#,dotnet-httpclient,C#,Dotnet Httpclient,我试图将一些数据发布到web服务,并在控制台应用程序中使用HttpClient接收响应。如果我尝试重用HttpClient实例,那么对PostAsJsonAsync的第一个调用将按预期工作,但第二个调用将永远等待。如果我为每个调用创建一个新的HttpClient,那么一切都正常 public class DirectHandler { HttpClient httpClient; public string SendToPlayer(object message) {

我试图将一些数据发布到web服务,并在控制台应用程序中使用HttpClient接收响应。如果我尝试重用HttpClient实例,那么对PostAsJsonAsync的第一个调用将按预期工作,但第二个调用将永远等待。如果我为每个调用创建一个新的HttpClient,那么一切都正常

public class DirectHandler
{
    HttpClient httpClient;

    public string SendToPlayer(object message)
    {

        if (httpClient == null)
        {
            httpClient = new HttpClient();
            httpClient.BaseAddress = new Uri("..url...");
        }

        HttpResponseMessage response = httpClient.PostAsJsonAsync("", message).Result;  // Blocking call!
        if (response.IsSuccessStatusCode)
        {
            var result = response.Content.ReadAsByteArrayAsync().Result;
            return System.Text.Encoding.Default.GetString(result);
        }
        else
        {
            throw new HttpRequestException("Error code " + response.StatusCode + ", reason: " + response.ReasonPhrase);
        }
    }
}
使用此类的代码:

DirectHandler dh = new DirectHandler();
var resp = dh.SendToPlayer(myObj);
Console.WriteLine("Received: " + resp);
Thread.Sleep(500);
resp = dh.SendToPlayer(myObj);
Console.WriteLine("Received: " + resp);
“服务器”是一个HttpListener:

public class HTTPServer
{
    void StartListener()
    {
        HttpListener listener = new HttpListener();
        listener.Prefixes.Add("my prefix");
        listener.Start();
        listener.BeginGetContext(new AsyncCallback(OnRequestReceive), listener);
    }

    private void OnRequestReceive(IAsyncResult result)
    {
        HttpListener listener = (HttpListener)result.AsyncState;

        HttpListenerContext context = listener.EndGetContext(result);
        HttpListenerResponse response = context.Response;
        HttpListenerRequest request = context.Request;

        using (var reader = new StreamReader(request.InputStream, request.ContentEncoding))
        {
            Console.WriteLine(reader.ReadToEnd());
        }

        string responseString = "{'a': \"b\"}";
        byte[] buffer = Encoding.UTF8.GetBytes(responseString);
        response.ContentLength64 = buffer.Length;
        response.OutputStream.Write(buffer, 0, buffer.Length);

        listener.BeginGetContext(new AsyncCallback(OnRequestReceive), listener);
    }
}
如何重用HttpClient

更新: 我将.Result更改为async/await,现在SendToPlayer方法如下所示:

public async Task<string> SendToPlayer(object message)
{
    if (httpClient == null)
    {
        httpClient = new HttpClient();
        httpClient.BaseAddress = new Uri("..url...");
    }

    HttpResponseMessage response = await httpClient.PostAsJsonAsync("", message).ConfigureAwait(false); 
    if (response.IsSuccessStatusCode)
    {
        var result = await response.Content.ReadAsByteArrayAsync();
        return System.Text.Encoding.Default.GetString(result);
    }
    else
    {
        throw new HttpRequestException("Error code " + response.StatusCode + ", reason: " + response.ReasonPhrase);
    }
}

我不得不注意到,您提供的代码甚至都没有编译。比如主方法中的
myObj
来自哪里?既然方法
StartListener
被声明为私有,那么您如何启动http侦听器呢? 这类问题使我怀疑您发布的代码不是具有所述问题的实际代码

另外,您在myObj中输入了什么内容

我复制并调整了你的代码,使它在我的机器上工作。请查看它是否在您的计算机上以及在新的控制台应用程序中运行(您需要管理员权限才能运行它)

现在,您可能已经简化了发布在此处的代码。如果有任何代码你没有张贴在这里,它将很难解决

您的
HttpListener
是否在单独的(控制台)应用程序中运行?可能服务器进程在第一次调用后终止,例如由于错误


如果上述代码在新的控制台应用程序中有效,请尝试查找与代码的差异。

在我看来,有两个问题:

1) 您的服务器需要等待处理多个事件,并且

2) 客户端和服务器代码应该驻留在单独的执行线程中

根据您编写的方式,服务器将在启动后不久关闭,这就是为什么第一个请求可以工作,但第二个请求挂起的原因

我创建了一个示例:

您必须首先启动服务器项目,它等待传入的请求(StartListening不会保持服务器线程打开,因此有一个while(IsRunning){thread.Sleep(100);}循环作为示例。

然后将客户端作为一个单独的进程启动,并观察它的控制台输出。它实际上会得到第二个响应(为什么会有5秒的延迟来让您看到这一点)。


希望这两个建议能有所帮助!

当使用async/wait时,不要等待使用.Result或.wait()的异步方法,始终使用
wait
。根据上下文中的环境。Result和.wait可能会导致死锁。我将代码重写为使用wait而不是.Result,但没有任何更改。我还尝试了.postasjsync(…).ConfigureAwait(false),但对它的第二个调用仍然挂起。显示您如何重写代码,以便我们可以看到您所做的操作。使用该类的代码现在显示
var resp=dh.SendToPlayer(myObj);
,这也应该等待:
var resp=await dh.SendToPlayer(myObj);
。调用该代码段的方法也需要一直等待。如果单击“暂停”,调试器会在哪一行停止?您可能需要打开“线程”窗口切换到后台线程。同时给我们一个“任务”的屏幕截图Windows when paused.myObj是一个简单的DTO,但现在我也使用了一个整数。你的代码对我也适用。最初我的StartListener是公共的,可能在格式化过程中意外删除了它。我的DirectHandler与你的完全一样,也是主方法。服务器在第一次调用后不会停止(它在Unity3D应用程序中)(这里可能有什么?),StartListener在启动时调用),如果我重新启动客户端,它会再次响应第一个请求,但OnRequestReceive不会由第二个PostsJSONASync触发。正如我所说的,如果我在每次SendToPlayer调用中创建一个新的HttpClient,它就会工作。
public static void Main(string[] args)
{
    Task.Run(async () =>
    {
        DirectHandler dh = new DirectHandler();
        var resp = await dh.SendToPlayer(myObj);
        Console.WriteLine("Received: " + str);
        Thread.Sleep(500);
        resp = await dh.SendToPlayer(myObj);
        Console.WriteLine("Received: " + str);

    }).Wait();
}
public static void Main(string[] args)
{
    var s = new HTTPServer();
    s.StartListener();

    Task.Run(async () =>
    {
        var myObj = 8;

        DirectHandler dh = new DirectHandler();
        var resp = await dh.SendToPlayer(myObj);
        Console.WriteLine("Received: " + resp);
        Thread.Sleep(500);
        resp = await dh.SendToPlayer(myObj);
        Console.WriteLine("Received: " + resp);

    }).Wait();
}

public class HTTPServer
{
    public void StartListener()
    {
        HttpListener listener = new HttpListener();
        listener.Prefixes.Add("http://*:8080/");
        listener.Start();
        listener.BeginGetContext(new AsyncCallback(OnRequestReceive), listener);
    }

    private void OnRequestReceive(IAsyncResult result)
    {
        HttpListener listener = (HttpListener)result.AsyncState;

        HttpListenerContext context = listener.EndGetContext(result);
        HttpListenerResponse response = context.Response;
        HttpListenerRequest request = context.Request;

        using (var reader = new StreamReader(request.InputStream, request.ContentEncoding))
        {
            Console.WriteLine(reader.ReadToEnd());
        }

        string responseString = "{'a': \"b\"}";
        byte[] buffer = Encoding.UTF8.GetBytes(responseString);
        response.ContentLength64 = buffer.Length;
        response.OutputStream.Write(buffer, 0, buffer.Length);

        listener.BeginGetContext(new AsyncCallback(OnRequestReceive), listener);
    }
}

public class DirectHandler
{
    HttpClient httpClient;

    public async Task<string> SendToPlayer(object message)
    {
        if (httpClient == null)
        {
            httpClient = new HttpClient();
            httpClient.BaseAddress = new Uri("http://localhost:8080");
        }

        HttpResponseMessage response = await httpClient.PostAsJsonAsync("", message).ConfigureAwait(false); 
        if (response.IsSuccessStatusCode)
        {
            var result = await response.Content.ReadAsByteArrayAsync();
            return System.Text.Encoding.Default.GetString(result);
        }
        else
        {
            throw new HttpRequestException("Error code " + response.StatusCode + ", reason: " + response.ReasonPhrase);
        }
    }
}
8
Received: {'a': "b"}
8
Received: {'a': "b"}