Поток файла с использованием ASP.NET MVC FileContentResult в браузере с именем?
Есть ли способ передать файл с помощью ASP.NET MVC FileContentResult в браузере с определенным именем?
Я заметил, что вы можете либо иметь FileDialog (Open/Save), либо вы можете передать файл в окне браузера, но затем он будет использовать ActionName при попытке сохранить файл.
У меня есть следующий сценарий:
byte[] contents = DocumentServiceInstance.CreateDocument(orderId, EPrintTypes.Quote);
result = File(contents, "application/pdf", String.Format("Quote{0}.pdf", orderId));
Когда я использую это, я могу передавать байты, но пользователю предоставляется диалоговое окно OPEN/SAVE. Я хотел бы фактически передать этот файл в окне браузера.
Если я просто использую FilePathResult, он отображает файл в окне браузера, но затем, когда я нажимаю кнопку "Сохранить", чтобы сохранить файл в формате PDF, он показывает мне имя действия как имя файла.
Кто-нибудь сталкивался с этим?
Ответы
Ответ 1
Это может быть полезно для тех, кто сталкивается с этой проблемой. Наконец я понял решение. Оказывается, даже если мы используем inline для "content-disposition" и укажите имя файла, браузеры все еще не используют имя файла. Вместо этого браузеры пытаются интерпретировать имя файла на основе пути /URL.
Вы можете прочитать далее по этому URL-адресу:
Секретная загрузка файла внутри браузера с правильным именем файла
Это дало мне представление, я только что создал свой URL-адрес, который преобразует URL-адрес и заканчивает его именем файла, который я хотел бы предоставить. Так, например, мой первоначальный вызов контроллера состоял только в том, чтобы передать идентификатор заказа печатаемого ордера. Я ожидал, что имя файла будет иметь формат Order {0}.pdf, где {0} - идентификатор заказа. Точно так же для цитат мне нужна Quote {0}.pdf.
В моем контроллере я просто пошел вперед и добавил дополнительный параметр, чтобы принять имя файла. Я передал имя файла как параметр в методе URL.Action.
Затем я создал новый маршрут, который отобразил бы этот URL-адрес в формат:
http://localhost/ShoppingCart/PrintQuote/1054/Quote1054.pdf
routes.MapRoute("", "{controller}/{action}/{orderId}/{fileName}",
new { controller = "ShoppingCart", action = "PrintQuote" }
, new string[] { "x.x.x.Controllers" }
);
Это в значительной степени решило мою проблему. Надеюсь, это поможет кому-то!
Cheerz,
Anup
Ответ 2
public ActionResult Index()
{
byte[] contents = FetchPdfBytes();
return File(contents, "application/pdf", "test.pdf");
}
и для открытия PDF внутри браузера вам нужно установить заголовок Content-Disposition
:
public ActionResult Index()
{
byte[] contents = FetchPdfBytes();
Response.AddHeader("Content-Disposition", "inline; filename=test.pdf");
return File(contents, "application/pdf");
}
Ответ 3
На самом деле, самый простой способ - сделать следующее...
byte[] content = your_byte[];
FileContentResult result = new FileContentResult(content, "application/octet-stream")
{
FileDownloadName = "your_file_name"
};
return result;
Ответ 4
Предыдущие ответы верны: добавление строки...
Response.AddHeader("Content-Disposition", "inline; filename=[filename]");
... приведет к тому, что несколько заголовков Content-Disposition будут отправлены в браузер. Это происходит, когда b/c FileContentResult
внутренне применяет заголовок, если вы снабжаете его именем файла. Альтернативным и довольно простым решением является просто создать подкласс FileContentResult
и переопределить его метод ExecuteResult()
. Вот пример, который создает экземпляр класса System.Net.Mime.ContentDisposition
(тот же объект, который используется во внутренней реализации FileContentResult
), и передает его в новый класс:
public class FileContentResultWithContentDisposition : FileContentResult
{
private const string ContentDispositionHeaderName = "Content-Disposition";
public FileContentResultWithContentDisposition(byte[] fileContents, string contentType, ContentDisposition contentDisposition)
: base(fileContents, contentType)
{
// check for null or invalid ctor arguments
ContentDisposition = contentDisposition;
}
public ContentDisposition ContentDisposition { get; private set; }
public override void ExecuteResult(ControllerContext context)
{
// check for null or invalid method argument
ContentDisposition.FileName = ContentDisposition.FileName ?? FileDownloadName;
var response = context.HttpContext.Response;
response.ContentType = ContentType;
response.AddHeader(ContentDispositionHeaderName, ContentDisposition.ToString());
WriteFile(response);
}
}
В Controller
или в базе Controller
вы можете написать простой помощник для создания экземпляра FileContentResultWithContentDisposition
, а затем вызвать его из вашего метода действий, например:
protected virtual FileContentResult File(byte[] fileContents, string contentType, ContentDisposition contentDisposition)
{
var result = new FileContentResultWithContentDisposition(fileContents, contentType, contentDisposition);
return result;
}
public ActionResult Report()
{
// get a reference to your document or file
// in this example the report exposes properties for
// the byte[] data and content-type of the document
var report = ...
return File(report.Data, report.ContentType, new ContentDisposition {
Inline = true,
FileName = report.FileName
});
}
Теперь файл будет отправлен в браузер с выбранным именем файла и с заголовком содержимого-содержимого "inline; filename = [filename]".
Я надеюсь, что это поможет!
Ответ 5
Абсолютно простым способом потоковой передачи файла в браузер с помощью ASP.NET MVC является следующее:
public ActionResult DownloadFile() {
return File(@"c:\path\to\somefile.pdf", "application/pdf", "Your Filename.pdf");
}
Это проще, чем метод, предложенный @azarc3, поскольку вам даже не нужно читать байты.
Кредит: http://prideparrot.com/blog/archive/2012/8/uploading_and_returning_files#how_to_return_a_file_as_response
** Изменить **
По-видимому, мой "ответ" совпадает с вопросом ОП. Но я не сталкиваюсь с проблемой, которую он испытывает. Вероятно, это была проблема со старой версией ASP.NET MVC?
Ответ 6
public FileContentResult GetImage(int productId) {
Product prod = repository.Products.FirstOrDefault(p => p.ProductID == productId);
if (prod != null) {
return File(prod.ImageData, prod.ImageMimeType);
} else {
return null;
}
}
Ответ 7
Как экспортировать в документ Word, используя метод Aspose.wrod? Прямо сейчас вот как мой метод экспорта в PDF:
var tnr = (EventService)RemotingHelper.GetObject(typeof(EventService));
string test= tnr.CreateEventReportForEventList(eventIDs, false, null, true);
byte[] eventData = System.Text.Encoding.UTF8.GetBytes(test);
MemoryStream ms = new MemoryStream(eventData);
Response.Cookies.Add(new HttpCookie("fileDownloadToken", "token"));
var doc = new Aspose.Words.Document(ms);
doc.Save(Response, "fileName.pdf", Aspose.Words.ContentDisposition.Attachment, null);
Response.End();