2017-03-10 65 views
4

希望有人能够启发我以下。asp.net核心1.1分块响应

我有一个客户端会向控制器端点发出请求(没有视图,c#到c#或甚至是C++)。该控制器必须发送响应,因为它以json的形式异步获取响应(将json1发送给客户端,然后发送json2,然后发送json3,直到它关闭连接或发送空终止文本或类似内容)。目的是将结果流回客户端,以便在服务器仍能正常工作时开始处理。

我的控制器端点看起来是这样的:

 [HttpGet("testStream")] 
     public async Task testStream() 
     { 
      var response = HttpContext.Response; 
      response.Headers[HeaderNames.TransferEncoding] = "chunked"; 


      for (var i = 0; i < 10; ++i) 
      { 
       await response.WriteAsync($"6\r\ntest {i}\r\n"); 

       await response.Body.FlushAsync(); 
       await Task.Delay(1 * 1000); 
      } 
      await response.WriteAsync("0\r\n\r\n"); 
      await response.Body.FlushAsync(); 
     } 

我的测试是这样的:

 static async void DownloadPageAsync() 
     { 
      // ... Target page. 
      string page = "http://localhost:8080/api/Stream/testStream"; 
      Console.WriteLine("test"); 
      while (!Debugger.IsAttached) Thread.Sleep(500); 
      // ... Use HttpClient. 
      using (HttpClient client = new HttpClient()) 
      using (var response = await client.GetAsync(page, HttpCompletionOption.ResponseHeadersRead)) 
      using (HttpContent content = response.Content) 
      { 
       string result = await content.ReadAsStringAsync(); 
       do 
       { 
        Console.WriteLine(result); 
        result = await content.ReadAsStringAsync(); 
       } 
       while (result != "null"); 
      } 
      Console.WriteLine("END"); 
     } 
     [Fact] 
     public void Test1() 
     { 
      TestSurvey.DownloadPageAsync(); 
     } 

我得到异常,当我打电话content.ReadAsStringAsync();

System.Net.Http.HttpRequestException : Error while copying content to a stream. 
[xUnit.net 00:01:14.5836121]  ---- System.IO.IOException : The read operation failed, see inner exception. 
[xUnit.net 00:01:14.5836496]  -------- System.Net.Http.CurlException : Failure when receiving data from the peer 
[xUnit.net 00:01:14.5846837]  Stack Trace: 
[xUnit.net 00:01:14.5857807]   at System.Net.Http.HttpContent.<LoadIntoBufferAsyncCore>d__48.MoveNext() 

编辑:异常是由于没有发送大块的大小 await response.WriteAsync($"6\r\ntest {i}\r\n");

,但现在在测试/客户端,我得到的所有数据块一次......

+0

为什么你让你的代码更少效率'等待Task.Delay(1 * 1000);'? – Liam

+1

基本上,不要这样做。只需将数据发回。如果需要,可以使用[HTTP将大块](https://en.wikipedia.org/wiki/Chunked_transfer_encoding)。你在这里做的所有事情都在减慢你的服务速度,而不是加快速度。 – Liam

+0

这是为了测试目的,我想看到答案缓慢回来...... – Jon

回答

3

为了解决这个问题,我利用SSE或服务器端事件。 这里是在asp.net核心服务器端:

 [HttpGet("testStream")] 
     public async Task testStream() 
     { 
      var response = HttpContext.Response; 
      response.StatusCode = 200; 
      response.ContentType = "text/event-stream"; 

      for (var i = 0; i < 10; ++i) 
      { 
       //the tags are either 'events:' or 'data:' and two \n indicates ends of the msg 
       //event: xyz \n\n 
       //data: xyz \n\n 
       await response.WriteAsync($"data: test {i}\n\n"); 

       response.Body.Flush(); 
       await Task.Delay(5 * 1000); 
      } 
      await response.WriteAsync("data:\n\n"); 
      await response.Body.FlushAsync(); 
     } 

,这里是客户端:

 string page = "http://localhost:8080/api/Stream/testStream"; 

     //while (!Debugger.IsAttached) Thread.Sleep(500); 

     using (HttpClient client = new HttpClient()) 
     using (var s = await client.GetStreamAsync(page)) 
     { 
      using (StreamReader r = new StreamReader(s)) 
      { 
       string line = null; 
       while (null != (line = r.ReadLine())) 
       { 
        Console.WriteLine(line); 
       } 
      } 
     } 

ReadAsStringAsync的使用迫使所有消息的等待才能继续。