2016-12-02 119 views
-1

我试图将一些数据发布到Web服务并在控制台应用程序中接收HttpClient的响应。如果我尝试重用一个HttpClient实例,PostAsJsonAsync的第一个调用按预期工作,但第二个只是等待。如果我为每个呼叫创建一个新的HttpClient,那么一切都可以。第二次调用HttpClient的PostAsJsonAsync stucks

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?

更新: 我改变了。结果到异步/ 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); 
    } 
} 

它仍然永远PostAsJsonAsync时多次调用等待。

UPDATE2:

测试代码,挂在第二SendToPlayer行:

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(); 
} 
+1

使用async/await时,不要等待使用.Result或.Wait()的异步方法时,请始终使用'await'。根据环境环境。结果和.Wait可能导致死锁。 –

+0

我重写了我的代码以使用await而不是.Result无处不在,但没有任何更改。我也试过.PostAsJsonAsync(...)。ConfigureAwait(false),但第二次调用它仍然挂起。 – gberes

+0

显示你如何重写代码,以便我们看到你做了什么。 – Nkosi

回答

1

我不禁注意到,你所提供的代码甚至不进行编译。像你主要方法中的myObj从哪里来的?你怎么开始http侦听器,因为方法StartListener被声明为私有? 这些类型的问题让我怀疑你发布的代码不是具有所描述问题的实际代码。

另外,你把什么放入myObj

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

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"} 

现在,你可能已简化您在此处发布的代码。如果有任何你没有发布的代码很难解决。

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

如果上面的代码在新的控制台应用程序中工作,请尝试查找与您的代码的区别。

+0

myObj是一个简单的DTO,但现在我也使用了一个整数。你的代码也适用于我。本来我的StartListener是公开的,可能在格式化时意外删除了它。我的DirectHandler和你的完全一样,也是主要的方法。服务器在第一次调用后不会停止(它在Unity3D应用程序中(可能是这里的东西?),StartListener在启动时调用),如果我重新启动客户端,它会再次响应第一个请求,但OnRequestReceive不会由第二个PostAsJsonAsync。正如我伤心,如果我在每个SendToPlayer调用中创建一个新的HttpClient,那么它的工作原理。 – gberes

0

在我看来,有两个问题:

1)您的服务器需要等待来自于处理不仅仅是一个事件多,

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

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

我创建了一个例子: https://github.com/paulsbruce/StackOverflowExamples/tree/master/SOF40934218

你必须先踢服务器项目关闭,这对于传入请求等待(StartListening不成立的服务器线程开放的,所以有一段时间(IsRunning ){Thread.Sleep(100);}循环为例 https://github.com/paulsbruce/StackOverflowExamples/blob/master/SOF40934218/SOF40934218_Server/Server.cs

然后启动客户端作为一个单独的进程,并观察它的控制台输出它实际上得到第二个响应(为什么有一个5第二次延迟让你看到这个) https://github.com/paulsbruce/StackOverflowExamples/blob/master/SOF40934218/SOF40934218_Client/Client.cs

希望这两个建议帮助!