Как загрузить CSV файл из ASP.NET Web Api с помощью jQuery Ajax call - программирование
Подтвердить что ты не робот

Как загрузить CSV файл из ASP.NET Web Api с помощью jQuery Ajax call

Я работаю над тем, как загрузить CSV файл из ASP.NET Web Api из jQuery ajax-вызова. CSV файл генерируется динамически с сервера веб-API на основе пользовательского CsvFormatter.

Ajax из jQuery:

   $.ajax({
        type: "GET",
        headers: {
            Accept: "text/csv; charset=utf-8",
        },
        url: "/api/employees",
        success: function (data) {
        }
    });

На сервере EmployeeCsvFormatter реализована аналогично следующей статье, полученной из BufferedMediaTypeFormatter:

http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters

public class EmployeeCsvFormatter : BufferedMediaTypeFormatter
{
    public EmployeeCsvFormatter()
    {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));
    }
    ...
}

Я также добавил метод переопределения, чтобы указать, что я хотел бы скачать как обычный способ загрузки файла (см. файл загрузки на вкладке загрузки):

 public override void SetDefaultContentHeaders(Type type, 
    HttpContentHeaders headers, MediaTypeHeaderValue mediaType)       
{
    base.SetDefaultContentHeaders(type, headers, mediaType);
    headers.Add("Content-Disposition", "attachment; filename=yourname.csv");
    headers.ContentType =  new MediaTypeHeaderValue("application/octet-stream");
}

Но это не работает, файл загрузки не отображается в строке состояния или на вкладке загрузки в Chrome, хотя из Fiddler я вижу, что ответ кажется правильным:

HTTP/1.1 200 OK
Server: ASP.NET Development Server/11.0.0.0
Date: Mon, 11 Mar 2013 08:19:35 GMT
X-AspNet-Version: 4.0.30319
Content-Disposition: attachment; filename=yourname.csv
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: application/octet-stream
Content-Length: 26
Connection: Close

1,Cuong,123
1,Trung,123

Мой метод от ApiController:

public EmployeeDto[] Get()
{
    var result = new[]
               {
                   new EmployeeDto() {Id = 1, Name = "Cuong", Address = "123"},
                   new EmployeeDto() {Id = 1, Name = "Trung", Address = "123"},
               };

    return result;
}

Это должно быть неправильно где-то, что я не понял. Как я могу заставить его работать, загружая CSV файл, как обычно?

4b9b3361

Ответ 1

JQuery плагин для запроса делает это без Ajax используя простую форму submit.

внутри

jQuery('<form action="'+ url +'" method="'+ (method||'post') +'">'+inputs+'</form>')
    .appendTo('body').submit().remove()

Он имеет интерфейс в стиле ajax, поэтому извне вы можете его так называть

$.download('/api/employees','format=csv');

Другой простой подход:

$('#btnDownload').click(function (e) {
    e.preventDefault();
    window.location = "/api/employees?format=csv";
});

На сервере MediaTypeMappings необходимо использовать, добавив еще один конструктор:

    public EmployeeCsvFormatter(MediaTypeMapping mediaTypeMapping)
        : this()
    {
        MediaTypeMappings.Add(mediaTypeMapping);
    }

Затем добавьте этот форматтер в конфигурацию Web Api:

   configuration.Formatters.Add(new EmployeeCsvFormatter
            (new QueryStringMapping("format", "csv", "text/csv")));

Ответ 2

В качестве альтернативного подхода можно загрузить загрузку нажатием кнопки anchor() или кнопки с запрошенным URL-адресом, заданным API, который отвечает вложением.

В CsvMediaTypeFormatter (Производится из System.Net.Http.Formatting.MediaTypeFormatter) помимо сопоставления типа MIME text/csv, как показано в ответах выше, я нашел следующее:

public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
        {
            base.SetDefaultContentHeaders(type, headers, mediaType);
            headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName = string.Concat("data", DateTime.UtcNow.ToString("yyyyMMddhhmmss"), ".csv")
            };

            headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        }

Примечание. При записи потока установите заголовок Content-Length и запомните "Слить поток". Я обнаружил, что без вызова Flush() возвращаемый ответ не возвращает его клиенту, даже когда была установлена ​​правильная длина содержимого.

Ответ 3

Вы также можете установить заголовок запроса в beforeSend, изменив xhr.

    $.ajax({
    url: "/api/employees",
    type: "GET",
    beforeSend: function (xhr) {
        xhr.setRequestHeader("Accept", "text/csv");
    },
    success: function (data) {
            }
    });