Estou com um problema ao enviar arquivos armazenados em um banco de dados de volta para o usuário no ASP.NET MVC. O que eu quero é uma visualização listando dois links, um para exibir o arquivo e permitir que o tipo de mim enviado ao navegador determine como ele deve ser tratado e o outro para forçar um download.
Se eu optar por exibir um arquivo chamado SomeRandomFile.bak
e o navegador não tiver um programa associado para abrir arquivos desse tipo, não tenho problemas com o padrão do comportamento do download. No entanto, se eu optar por exibir um arquivo chamado SomeRandomFile.pdf
ou SomeRandomFile.jpg
desejar que ele seja simplesmente aberto. Mas também quero manter um link de download ao lado para poder forçar um prompt de download, independentemente do tipo de arquivo. Isso faz sentido?
Eu tentei FileStreamResult
e funciona para a maioria dos arquivos; seu construtor não aceita um nome de arquivo por padrão; portanto, arquivos desconhecidos recebem um nome de arquivo com base na URL (que não conhece a extensão a ser atribuída com base no tipo de conteúdo). Se forçar o nome do arquivo especificando-o, perco a capacidade do navegador de abrir o arquivo diretamente e recebo uma solicitação de download. Mais alguém encontrou isso?
Estes são os exemplos do que eu tentei até agora.
//Gives me a download prompt.
return File(document.Data, document.ContentType, document.Name);
//Opens if it is a known extension type, downloads otherwise (download has bogus name and missing extension)
return new FileStreamResult(new MemoryStream(document.Data), document.ContentType);
//Gives me a download prompt (lose the ability to open by default if known type)
return new FileStreamResult(new MemoryStream(document.Data), document.ContentType) {FileDownloadName = document.Name};
Alguma sugestão?
ATUALIZAÇÃO:
Essas perguntas parecem impressionar muita gente, então pensei em publicar uma atualização. O aviso na resposta aceita abaixo, que foi adicionado por Oskar em relação aos personagens internacionais, é completamente válido, e eu o recebi algumas vezes devido ao uso da ContentDisposition
classe. Atualizei minha implementação para corrigir isso. Embora o código abaixo seja da minha versão mais recente desse problema em um aplicativo ASP.NET Core (Full Framework), ele deve funcionar com alterações mínimas em um aplicativo MVC mais antigo, desde que eu esteja usando a System.Net.Http.Headers.ContentDispositionHeaderValue
classe.
using System.Net.Http.Headers;
public IActionResult Download()
{
Document document = ... //Obtain document from database context
//"attachment" means always prompt the user to download
//"inline" means let the browser try and handle it
var cd = new ContentDispositionHeaderValue("attachment")
{
FileNameStar = document.FileName
};
Response.Headers.Add(HeaderNames.ContentDisposition, cd.ToString());
return File(document.Data, document.ContentType);
}
// an entity class for the document in my database
public class Document
{
public string FileName { get; set; }
public string ContentType { get; set; }
public byte[] Data { get; set; }
//Other properties left out for brevity
}
fonte
Inline = true
certifique-se de NÃO usar a sobrecarga de 3 parâmetrosFile()
que leva o nome do arquivo como o 3º parâmetro. Ele vai funcionar no IE, mas o Chrome irá relatar um cabeçalho duplicado e recusar-se a apresentar a imagem.Eu tive problemas com a resposta aceita devido a nenhum tipo de sugestão na variável "document":
var document = ...
Portanto, estou postando o que funcionou para mim como uma alternativa no caso de alguém mais estar tendo problemas.fonte
AppDomain.CurrentDomain.BaseDirectory
é queSystem.Web.HttpContext.Current.Server.MapPath("~")
isso funcione melhor em um servidor real comparado a uma máquina local.A resposta de Darin Dimitrov está correta. Apenas uma adição:
Response.AppendHeader("Content-Disposition", cd.ToString());
pode causar falha no navegador ao renderizar o arquivo se sua resposta já contiver um cabeçalho "Disposição de conteúdo". Nesse caso, você pode querer usar:fonte
pdf
arquivo, se eu definir o tipo de conteúdoSystem.Net.Mime.MediaTypeNames.Application.Octet
, forçará o download mesmo quando eu definirInline = true
, mas se eu definir comoResponse.ContentType = MimeMapping.GetMimeMapping(filePath)
, ou sejaapplication/pdf
, ele poderá abrir corretamente em vez de baixarResponse.Headers.Add
requer o modo de pipeline integrado do IIS. Além disso, mesmo se o pool de aplicativos estiver definido como integrado, ele lançará uma exceção. Solução. UseResponse.AddHeader
. Veja SO thread: stackoverflow.com/questions/22313167/…Para visualizar o arquivo (txt por exemplo):
Para baixar o arquivo (txt por exemplo):
note: para baixar o arquivo, devemos passar o argumento fileDownloadName
fonte
Inline
propriedade Disposição de conteúdo permite separar a capacidade de definir o nome do arquivo do comportamento de forçar o download ou não.Acredito que esta resposta seja mais limpa (com base em https://stackoverflow.com/a/3007668/550975 )
fonte
application/octet-stream
e isso ainda fez com que o arquivo fosse baixado em vez de mostrado, e parece ser compatível.FileVirtualPath -> Pesquisa \ Global Office Review.pdf
fonte
O código abaixo funcionou para mim para obter um arquivo pdf de um serviço de API e respondê-lo ao navegador - espero que ajude;
fonte
Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider
O método de ação precisa retornar o FileResult com um fluxo, byte [] ou caminho virtual do arquivo. Você também precisará conhecer o tipo de conteúdo do arquivo que está sendo baixado. Aqui está um método de utilitário de amostra (rápido / sujo). Exemplo de link de vídeo Como baixar arquivos usando o núcleo do asp.net
fonte
Se, como eu, você chegou a esse tópico através dos componentes do Razor enquanto aprende o Blazor, verá que precisa pensar um pouco mais fora da caixa para resolver esse problema. É um campo minado se (também como eu) o Blazor é sua primeira entrada no mundo do tipo MVC, pois a documentação não é tão útil para essas tarefas "domésticas".
Portanto, no momento da redação deste artigo, você não pode fazer isso usando o Blazor / Razor baunilha sem incorporar um controlador MVC para lidar com a parte de download de arquivos, um exemplo do qual é o seguinte:
Em seguida, verifique se a inicialização do aplicativo (Startup.cs) está configurada para usar corretamente o MVC e tem a seguinte linha presente (adicione-a, se não):
.. e, finalmente, modifique seu componente para vincular ao controlador, por exemplo (exemplo baseado em iterativo usando uma classe personalizada):
Espero que isso ajude qualquer um que lutou (como eu!) A obter uma resposta apropriada para essa pergunta aparentemente simples nos reinos de Blazor…!
fonte