12

我已经在我的 ASP.Net Web API 项目中成功实现了一个 Csv 媒体类型格式化程序。我能够以 Csv 格式返回结果。但是,生成的文件名是没有扩展名的“部分”。

理想情况下,我希望能够在控制器中设置此文件名,但能够在全局范围内添加扩展名将是最低要求。

以下是我找到的示例

覆盖 OnGetResponseHeaders - 我不认为这是当前版本中的选项。 http://forums.asp.net/t/1782973.aspx/1?Setting+response+and+content+headers+esp+ContentDisposition+inside+a+MediaTypeFormatter

根据那篇文章,这应该有效

public override IEnumerable<KeyValuePair<string, string>> OnGetResponseHeaders(Type objectType, string mediaType, HttpResponseMessage responseMessage)
{
       return new[] { new KeyValuePair<string, string>("Content-Disposition", "attachment; filename=testing.csv") };
}

然而,Visual Studio 说“没有合适的覆盖方法”并且当我将它添加到我的自定义 Csv 格式化程序时不会编译。

从控制器返回 HttpMessageResponse -如何在 ASP.NET Web API 中设置下载文件名 然而,这似乎只是在推送现有的服务器文件,这将使 Csv 序列化脱离混合。下面是使这种方法起作用的尝试:

public HttpResponseMessage Get(string id)
{
    var response = new HttpResponseMessage();

    if (id == "test")
    {
        var data = GetTestData();
        response.StatusCode = HttpStatusCode.OK;
        response.Content = new StreamContent(data);
        response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
        response.Content.Headers.ContentDisposition.FileName = "testorama.csv";
        return response;
    }

    return null;
}

这里的问题是 new StreamContent() 需要一个流 - 有没有办法获取 Custom Csv Formatter 创建的当前流?

底线,如何为首先序列化为 Csv 格式的结果集设置文件名?

解决方案

谢谢克劳迪奥——这让我朝着正确的方向前进。与您发布的内容相比有一些变化:

  1. 我从 BufferedMediaTypeFormatter 派生了我的自定义 Csv Formatter,而要使用 SetDefaultContentHeaders,我不得不从 MediaTypeFormatter 派生。

  2. SetDefaultContentHeaders 接受类型为 MediaTypeHeaderValue 而不是字符串的 mediaType 参数。

这是最终代码:

public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
{
    base.SetDefaultContentHeaders(type, headers, mediaType);
    headers.Add("Content-Disposition", "attachment; filename=testorama.csv");
}
4

2 回答 2

15

覆盖SetDefaultContentHeadersMediaTypeFormatter 上的方法

public override void SetDefaultContentHeaders(
    Type type, HttpContentHeaders headers, string mediaType)
{
    base.SetDefaultContentHeaders(type, headers, mediaType);
    headers.Add("Content-Disposition", "attachment; filename=yourname.csv");
}
于 2012-09-07T21:19:09.827 回答
7

为了提供基于数据的自定义名称(至少在 Web API 2 中),您需要覆盖 GetPerRequestFormatterInstance。从那里您可以访问 HttpRequestMessage。

private string FileName { get; set; }

public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
{
    base.SetDefaultContentHeaders(type, headers, mediaType);
    if (!string.IsNullOrEmpty(FileName))
        headers.Add("Content-Disposition", string.Format("attachment; filename={0}", FileName));
}

public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType)
{
    // We aren't setting the name, so just return the current instance.
    if (!request.Properties.ContainsKey("filename")) return this;

    var formatter = new CsvFormatter();
    var fileName = request.Properties["filename"] as string;
    formatter.FileName = string.Format("{0}.csv", fileName);
    return formatter;
}

然后,在您的控制器操作中,您可以像这样设置文件名......

if (!Request.Properties.ContainsKey("filename"))
    Request.Properties.Add("filename", "MyFile.{ext}");

我使用 {ext} 以防我添加需要文件名的其他格式化程序。理论上,只有扩展名才需要更改以支持其他格式。

于 2014-03-12T01:40:31.520 回答