Web API方法如何调用另一个流内容的Web API方法?

3

以下是我的情况说明:我有两个Web API服务。第一个服务有一个方法,用于处理一些数据,当部分数据准备好后,它将其推送到流中。

public HttpResponseMessage Get( )
        {
            var response = Request.CreateResponse( );
            response.Content = new PushStreamContent( WriteToStream );
            return response;
        }

        public async void WriteToStream( Stream outputStream, HttpContent content, TransportContext context )
        {
            .......
        }

第二个Web API 在控制器中有一个方法,调用第一个Web API。它必须从流中读取数据并对其进行处理,并将其放入自己的流中:

public HttpResponseMessage Get( )
        {
            Stream stream = null;

            using( HttpClient httpClient = new HttpClient( ) )
            {
                httpClient.Timeout = TimeSpan.FromMilliseconds( Timeout.Infinite );
                HttpRequestMessage request = new HttpRequestMessage( HttpMethod.Get, "http://localhost/fistWebApi/" );

                var response = httpClient.SendAsync( request, HttpCompletionOption.ResponseContentRead );

                var content = response.Result.Content.ReadAsStreamAsync( );

                stream = content.Result;
            }

            var msg = Request.CreateResponse( );

            msg.Content = new PushStreamContent( WriteToStream );

            return msg;
        }
public async void WriteToStream( Stream outputStream, HttpContent content, TransportContext context )
            {
                .......
            }

问题在于我不知道如何同步调用 SendAsyncReadAsStreamAsync。现在,代码不会等待,当尝试使用 stream 时,它并没有正确初始化。我希望第二个方法的代码等待第一个方法将数据的一部分放入流中。我尝试过使用 ContinueWith,但是我无法做到这一点。如果有任何问题,请告诉我,我会详细解释。
1个回答

10

试试这个...

 public HttpResponseMessage Get()
        {

            using (HttpClient httpClient = new HttpClient())
            {
                httpClient.Timeout = TimeSpan.FromMilliseconds(Timeout.Infinite);
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://www.google.ca");

                return httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead)
                    .ContinueWith((t) =>
                        {
                            return new HttpResponseMessage()
                                {
                                    Content = t.Result.Content
                                };
                        }).Result;

            }

        }

上面的代码对我来说很有效。但这种方法的缺点是,因为你使用了HttpCompletionOption.ResponseContentRead,所以从远程服务返回的整个负载将在将其返回给客户端之前被缓冲。

如果改用HttpCompletionOption.ResponseHeadersReadt.Result.Content将返回一个网络流。这样,当客户端拉取响应流时,它将直接从远程资源进行流式传输。我假设这就是你目前尝试使用的PushStreamContent要返回的内容。


你不应该通过将状态码传递给构造函数来转发状态码吗?例如:new HttpResponseMessage(t.result.StatusCode) - Steve Vermeulen
2
@eventualEntropy 是的。并复制头文件。通过将方法设置为异步来消除那些讨厌的.Result调用。这段代码有很多问题。 - Darrel Miller
1
非常好的答案,我正在构建两个API之间的“代理”,并且一直在努力寻找一种在不将整个文件缓冲到RAM中的情况下流式传输大文件的方法,这就是解决方案!我发现一个重要的注意事项:如果您在Web Api自托管项目中使用此功能,请确保还延长HttpSelfHostConfiguration对象的超时时间,否则持续时间超过60秒的请求将失败。 - Master_T
在下载大文件时,会产生网络错误。 - Power Star

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接