Asp.net Web API - Как установить имя файла для настраиваемого формата CSV Media Type Formatter

Я успешно реализовал формат Csv Media Type Formatter в моем проекте ASP.Net Web API. Я могу получить результаты в формате 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 Formatter.

Возврат HttpMessageResponse от контроллера - Как установить загрузку имени файла в веб-API ASP.NET Однако, похоже, это просто толкает существующие файлы сервера, что приведет к сериализации 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;
}

Проблема в том, что новый StreamContent() ожидает поток - есть ли способ получить текущий поток, созданный Custom Csv Formatter?

В нижней строке, как я могу установить имя файла для набора результатов, который сначала сериализуется в формате Csv?

Решение

Спасибо Клаудио - это заставило меня двигаться в правильном направлении. Пара изменится с того, что вы разместили:

  • Я извлекал из BufferedMediaTypeFormatter для своего пользовательского Csv Formatter и использовать SetDefaultContentHeaders мне пришлось вместо этого вытекает из MediaTypeFormatter.

  • SetDefaultContentHeaders принимает параметр mediaType с типом   MediaTypeHeaderValue, а не строка.

Вот окончательный код:

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

Ответ 1

Отмените метод SetDefaultContentHeaders на свой MediaTypeFormatter

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

Ответ 2

Чтобы создать собственное имя на основе данных (по крайней мере, в 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} в случае добавления дополнительных форматировщиков, которым требуется имя файла. Теоретически, только расширение должно измениться для поддержки других форматов.