Як встановити ім'я файлу для завантаження у веб-API ASP.NET


140

У моєму класі ApiController я маю наступний спосіб завантажити файл, створений сервером.

public HttpResponseMessage Get(int id)
{
    try
    {
        string dir = HttpContext.Current.Server.MapPath("~"); //location of the template file
        Stream file = new MemoryStream();
        Stream result = _service.GetMyForm(id, dir, file);
        if (result == null)
        {
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }
        result.Position = 0;
        HttpResponseMessage response = new HttpResponseMessage();
        response.StatusCode = HttpStatusCode.OK;
        response.Content = new StreamContent(result);
        return response;
    }
    catch (IOException)
    {
        return Request.CreateResponse(HttpStatusCode.InternalServerError);
    }
}

Все працює ідеально, за винятком того, що ім'я файлу для завантаження за замовчуванням - це його ідентифікатор, тому користувачеві, можливо, доведеться кожного разу вводити своє власне ім’я файлу при збереженні як діалог. Чи є спосіб встановити ім'я файлу за замовчуванням у наведеному вище коді?


1
Чи можете ви поділитися кодом, який ви використовували для виклику цього методу?
Ясер Шейх

@Yasser - це метод контролера веб-API - він, ймовірно, викликається через HTTP-запити, що надходять у IIS, і аналізують їх, і знаходять маршрути та веб-API, що викликають метод (і, звичайно, його також викликають тести).
Дейв Реель

що відбувається всередині GetMyForm ()? Перетворення файлів у потік байтів?
MSIslam

@MSIslam Сортування. Функція отримує інформацію з форми користувача та створює файл перед переходом в отриманий потік.
Tae-Sung Shin

Відповіді:


289

Вам потрібно встановити Content-Dispositionзаголовок на HttpResponseMessage:

HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.OK;
response.Content = new StreamContent(result);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
    FileName = "foo.txt"
};

21
Для всіх, хто цікавиться типом диспозиції "вкладення", повний перелік типів розпорядження знаходиться на iana.org/assignments/cont-disp/cont-disp.xhtml
sfuqua

1
У вас є ще одна відповідь на завантаження файлу тут. Чи має значення ви використовуєте System.Net.Mime.ContentDispositionчи ContentDispositionHeaderValue? Є один більш сучасний і більш кращий, ніж інший?
Світле

@Luminous одна відповідь - для ActionResult, HttpResponseMessage
weston

@weston, ваша відповідь не відповідає на моє запитання.
Світлий

4
@Luminous "Чи це має значення" та "Чи є один більш сучасний і більш кращий, ніж інший?" Ні, і ні. Один призначений для MVC ActionResult, а один - для WebApi HttpResponseMessages.
Вестон

27

РЕДАКТУВАННЯ: Як згадується в коментарі, моя відповідь не враховує символів, яких потрібно уникати як ;. Ви повинні використовувати прийняту відповідь, яку Дарин зробив, якщо ваше ім'я файлу могло містити напівкрапку.

Додайте Response.AddHeader, щоб встановити ім'я файлу

Response.AddHeader("Content-Disposition", "attachment; filename=*FILE_NAME*");

Просто змініть FILE_NAME на ім'я файлу.


2
Це виявилося для мене корисним у вирішенні аналогічної проблеми як у запитувача. У моєму випадку я також вважаю корисним змінити "вкладення" на "вбудований", щоб IE8 дав мені можливість завжди відкривати відповідний тип файлу.
Скотт

2
Не охоплює втечу. Що робити, якщо ім'я файлу містить ;або щось інше зі спеціальним значенням?
Сем

Сем, У той час, коли я писав цю відповідь 3 роки тому, я не розумів, що моя відповідь потрібна для втечі. Дякую, що ви вказали на це, я змінив свою відповідь, пояснивши, що моя відповідь не пояснює втечу. Але зберігати мою відповідь тим самим, оскільки, здавалося, це допомагало людям.
KingPancake

8

Якщо ви хочете переконатися, що ім'я файлу правильно закодовано, але також уникати WebApi HttpResponseMessage, ви можете скористатися наступним:

Response.AddHeader("Content-Disposition", new System.Net.Mime.ContentDisposition("attachment") { FileName = "foo.txt" }.ToString());

Ви можете використовувати або ContentDisposition, або ContentDispositionHeaderValue. Виклик ToString за інстанцією будь-якого з них зробить кодування імен файлів для вас.


6

Я думаю, що це може вам бути корисним.

Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName)

4
Не охоплює втечу. Що робити, якщо ім'я файлу містить ;або щось інше зі спеціальним значенням?
Сем

3

Вам потрібно додати заголовок вмісту-диспозиції до відповіді:

 response.StatusCode = HttpStatusCode.OK;
 response.Content = new StreamContent(result);
 response.AppendHeader("content-disposition", "attachment; filename=" + fileName);
 return response;

3
Не охоплює втечу. Що робити, якщо ім'я файлу містить ;або щось інше зі спеціальним значенням?
Сем

3

Якщо ви використовуєте ASP.NET Core MVC, відповіді, наведені вище, колись настільки незначно змінені ...

У своєму методі дії (який повертається async Task<JsonResult>) я додаю рядок (будь-де до заяви про повернення):

Response.Headers.Add("Content-Disposition", $"attachment; filename={myFileName}");

Не охоплює втечу. Що робити, якщо ім'я файлу включає: чи щось інше з особливим значенням?
KoalaBear

2

Це слід зробити:

Response.AddHeader("Content-Disposition", "attachment;filename="+ YourFilename)

2
Не охоплює втечу. Що робити, якщо ім'я файлу містить ;або щось інше зі спеціальним значенням?
Сем

0

Примітка: Останній рядок є обов'язковим.

Якщо ми не вказали заголовки Access-Control-Expose , ми не отримаємо Ім'я файлу в інтерфейсі користувача.

FileInfo file = new FileInfo(FILEPATH);

HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
    FileName = file.Name
};
response.Content.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");

0

Розглядаючи попередні відповіді, потрібно бути обережними з глобалізованими символами.

Припустимо, ім'я файлу: " Esdrújula prenda ñame - güena.jpg "

Сирий результат для завантаження: "Esdrújula prenda à ± ame - güena.jpg" [Некрасиво]

Результат HtmlEncode для завантаження: "Esdr & _250; jula prenda & _241; ame - g & _252; ena.jpg" [Некрасиво]

Результат UrlEncode для завантаження: " Esdrújula + prenda + ñame + - + güena.jpg " [OK]

Тоді вам потрібно майже завжди використовувати UrlEncode над іменем файлу . Крім того, якщо ви встановите заголовок диспозиції вмісту як прямий рядок, вам потрібно забезпечити об'єм цитатами, щоб уникнути проблем із сумісністю браузера.

Response.AddHeader("Content-Disposition", $"attachment; filename=\"{HttpUtility.UrlEncode(YourFilename)}\"");

або за допомогою класу:

var cd = new ContentDisposition("attachment") { FileName = HttpUtility.UrlEncode(resultFileName) };
Response.AddHeader("Content-Disposition", cd.ToString());

Система.Net.Mime. Клас ContentDisposition піклується про цитати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.