【问题标题】:Web API HttpResponseMessage content return is incompleteWeb API HttpResponseMessage 内容返回不完整
【发布时间】:2013-11-26 18:19:07
【问题描述】:

我想返回使用 Web API 5.0 从我的数据库生成的 csv 除了返回的 csv 被截断之外,它工作正常。

我认为问题出在 MemoryBuffer 管理上,但我找不到问题所在。

我的代码(已解决):

        IEnumerable<MasterObsTrip> masterTripList = _obsvMasterRepo.GetObsTrips(vesselName, dateYear, port, obsvCode, obsvTripCode, obsvProgCode, lastModifiedDateYear, lastModifiedBy, statusCode);
        IList<MasterObsTripModel> masterTripModelList = new List<MasterObsTripModel>();
        foreach (MasterObsTrip trip in masterTripList)
            masterTripModelList.Add(new MasterObsTripModel(trip));

        var stream = new MemoryStream();
        var writer = new StreamWriter(stream);

        CsvFileDescription outputFileDescription = new CsvFileDescription
        {
            SeparatorChar = ',', // comma delimited
            FirstLineHasColumnNames = true, // no column names in first record
            FileCultureName = "nl-NL" // use formats used in The Netherlands
        };
        CsvContext cc = new CsvContext();
        cc.Write(masterTripModelList,writer,outputFileDescription);
        writer.Flush();
        stream.Position = 0;
        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
        response.Content = new StreamContent(stream);
        response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
        response.Content.Headers.ContentDisposition.FileName = "ObserverTripList.csv";
        stream.Flush();
        return response;

谢谢

【问题讨论】:

  • 避免调用stream.Flush(),因为对流的实际写入发生在稍后...尝试看看这是否能解决您的问题..
  • 感谢 Kiran,但删除流。Flush 不会改变任何东西
  • 嗯,好的……我觉得其他一切都还可以……只是为了确保,您是否尝试过查看内存流中的实际内容并查看它是否包含全部内容?您可以尝试将此内存流写入磁盘文件,看看它是否确实包含全部内容...
  • 是的,我在服务器上生成了文件,它包含我的整个数据集
  • 嗯,我不确定发生了什么...您可以分享一个复制品吗? (您使用的是哪个版本的 Web API?)

标签: c# asp.net-web-api httpresponse


【解决方案1】:

我会在你重置 stream.Position = 0 之前尝试执行 writer.Flush()

另外,如果您经常需要 CSV 内容,我还建议您自己创建一个 CsvContent 类。

public class CsvContent<T> : HttpContent
    {
        private readonly MemoryStream _stream = new MemoryStream();
        public CsvContent(CsvFileDescription outputFileDescription, string filename, IEnumerable<T> data)
        {
            var cc = new CsvContext();
            var writer = new StreamWriter(_stream);
            cc.Write(data, writer, outputFileDescription);
            writer.Flush();
            _stream.Position = 0;

            Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
            Headers.ContentDisposition.FileName = filename;

        }
        protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
        {
            return _stream.CopyToAsync(stream);
        }

        protected override bool TryComputeLength(out long length)
        {
            length = _stream.Length;
            return true;
        }
    }

然后你的控制器动作减少到...

IEnumerable<MasterObsTrip> masterTripList = _obsvMasterRepo.GetObsTrips(vesselName, dateYear, port, obsvCode, obsvTripCode, obsvProgCode, lastModifiedDateYear, lastModifiedBy, statusCode);
        IList<MasterObsTripModel> masterTripModelList = new List<MasterObsTripModel>();
        foreach (MasterObsTrip trip in masterTripList)
            masterTripModelList.Add(new MasterObsTripModel(trip));

        CsvFileDescription outputFileDescription = new CsvFileDescription
        {
            SeparatorChar = ',', // comma delimited
            FirstLineHasColumnNames = true, // no column names in first record
            FileCultureName = "nl-NL" // use formats used in The Netherlands
        };
        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK) {
           Content = new CsvContent<MasterObsTripModel> (outputFileDescription, 
                                                      "ObserverTripList.csv", 
                                                       masterTripModelList);
        }
        return response;

这可以通过在 CsvContent 类中包含 CsvFileDescription 的创建来进一步简化。

【讨论】:

  • 有这样的讨论 - stackoverflow.com/questions/15334227/… 建议使用 MediaTypeFormatter 对来自 ApiController 的返回进行序列化(并在需要时进行反序列化)。只是好奇,您如何将其与(我猜)控制器返回类型是 Csv 流的方法进行比较?
  • @mishrsud 我返回 HttpResponseMessage 并将 Content 属性设置为 CSVContent 实例。这允许我访问响应标头消息。
猜你喜欢
  • 2015-02-21
  • 2019-01-29
  • 1970-01-01
  • 2014-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多