如何使用 memorystream web return xlsx 文件 api

how to return a xlsx file using memorystream web api

我正在成功发出 Web 请求、创建 xlsx 文件并将其保存到目录中。我想将其流式传输并 return 到客户端,而不实际将其保存在服务器上。

这是我目前使用的,效果很好

  private string generateStudyTemplate(string requestId)
    {
        var serviceUrl = ConfigurationManager.AppSettings["serviceUrl"];

        // create webRequest
        HttpWebRequest webRequest = createWebRequest(serviceUrl + "/" + requestId);

        // begin async call to web request
        IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);

        // suspend this thread until call is complete. You might want to
        // do something usefull here like update your UI
        asyncResult.AsyncWaitHandle.WaitOne();

        // get the response from the completed web request
        var filename = string.Format("{0}.xlsx", "NewWorkbook");
        string physicalPath = HttpContext.Current.Server.MapPath("/FilesForExport");
        string relativePath = Path.Combine(physicalPath, filename).Replace("\", "/");
        var filePath = relativePath;

       // var filePath = directory + "\NewWorkbook.xlsx";
        using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
        {
            var str = webResponse.GetResponseStream();
            var inBuf = new byte[webResponse.ContentLength];
            var bytesToRead = Convert.ToInt32(inBuf.Length);
            var bytesRead = 0;
            while (bytesToRead > 0)
            {
                var n = str.Read(inBuf, bytesRead, bytesToRead);
                if (n == 0)
                    break;

                bytesRead += n;
                bytesToRead -= n;
            }

            var fstr = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write);
            fstr.Write(inBuf, 0, bytesRead);
            fstr.Close();
        }

        return filePath;
    }

    private static HttpWebRequest createWebRequest(string url)
    {
        HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
        webRequest.ContentType = "text/xml;charset=\"utf-8\"";
        webRequest.Accept = "text/xml";
        webRequest.Method = "GET";
        return webRequest;
}

这是我从其他一些例子中整理出来的。

 public HttpResponseMessage GenerateMarketStudyResult([FromBody]Result id)
    {
        if (id.requestId == null)
        {
            throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest));
        }
        var serviceUrl = ConfigurationManager.AppSettings["serviceUrl"];

        var streamContent = new PushStreamContent((outputStream, httpContext, transportContent) =>
        {
            try
            {
                HttpWebRequest webRequest = createWebRequest(serviceUrl + "/" + id.requestId);
                IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);
                asyncResult.AsyncWaitHandle.WaitOne();

                using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
                {
                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                        var str = webResponse.GetResponseStream();
                        var inBuf = new byte[webResponse.ContentLength];
                        var bytesToRead = Convert.ToInt32(inBuf.Length);
                        var bytesRead = 0;
                        while (bytesToRead > 0)
                        {
                            var n = str.Read(inBuf, bytesRead, bytesToRead);
                            if (n == 0)
                                break;

                            bytesRead += n;
                            bytesToRead -= n;
                        }
                        memoryStream.Write(inBuf, 0, bytesRead);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                outputStream.Close();
            }
        });
        streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
        streamContent.Headers.ContentDisposition.FileName = "reports.xlsx";

        var result = new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = streamContent
        };
        return result;

    }

我没有收到任何异常,但 xlsx 文件 returning 为 0 字节。

断点在这里

memoryStream.Write(inBuf, 0, bytesRead);

这里是 javascript 服务 returned 文件

   $http.post('/api/GenerateMarketStudyResult/', Result, { responseType: 'arraybuffer' })
                   .success(function (response, status, headers, config) {
                       saveAs(new Blob([response], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), 'reports.xlsx');
                   })

表明

bytesRead = 112336

我假设您编写了一个网络服务,作为您的 JavaScript 和某些第三方网络服务之间的代理。

首先,如果您至少使用 .NET 4.0,则可以使用 Stream.CopyTo 方法将一个流复制到另一个流。 所以不是这个:

using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
{
    var str = webResponse.GetResponseStream();
    var inBuf = new byte[webResponse.ContentLength];
    var bytesToRead = Convert.ToInt32(inBuf.Length);
    var bytesRead = 0;
    while (bytesToRead > 0)
    {
        var n = str.Read(inBuf, bytesRead, bytesToRead);
        if (n == 0) break;
        bytesRead += n;
        bytesToRead -= n;
    }
    var fstr = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write);
    fstr.Write(inBuf, 0, bytesRead);
    fstr.Close();
}

你可以这样写:

using (var webResponse = webRequest.EndGetResponse(asyncResult))
using (var fstr = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write)) 
{
    webResponse.GetResponseStream().CopyTo(fstr);
}

其次,假设您使用 WCF 构建 Web 服务,您可以将响应通过管道传输到内存流,然后 return 它。 (写完后不要忘记重置流的位置)

合计:

[WebGet(UriTemplate = "GenerateMarketStudyResult/{id}")]
public Stream GenerateMarketStudyResult(string id)
{
    var serviceUrl = ConfigurationManager.AppSettings["serviceUrl"];

    // create webRequest
    HttpWebRequest webRequest = createWebRequest(serviceUrl + "/" + id);

    // begin async call to web request
    IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);

    // suspend this thread until call is complete. You might want to
    // do something usefull here like update your UI
    asyncResult.AsyncWaitHandle.WaitOne();

    var memStream = new MemoryStream();
    // var filePath = directory + "\NewWorkbook.xlsx";
    using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
    {
        webResponse.GetResponseStream().CopyTo(memStream);
    }
    memStream.Position = 0;

    var response = WebOperationContext.Current.OutgoingResponse;
    response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    response.ContentLength = (int)memStream.Length;
    return memStream;
}

编辑: 您没有将 memoryStream 的内容复制到 outputStream。您可以省略 memoryStream。试试这个:

public HttpResponseMessage GenerateMarketStudyResult([FromBody]Result id)
{
    if (id.requestId == null)
    {
        throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest));
    }
    var serviceUrl = ConfigurationManager.AppSettings["serviceUrl"];

    var streamContent = new PushStreamContent((outputStream, httpContext, transportContent) =>
    {
        try
        {
            HttpWebRequest webRequest = createWebRequest(serviceUrl + "/" + id.requestId);
            IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);
            asyncResult.AsyncWaitHandle.WaitOne();

            using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
            {
                webResponse.GetResponseStream().CopyTo(outputStream);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        finally
        {
            outputStream.Close();
        }
    });
    streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
    streamContent.Headers.ContentDisposition.FileName = "reports.xlsx";

    var result = new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = streamContent
    };
    return result;
}