web-dev-qa-db-fra.com

Comment renvoyer un fichier Excel à partir d'un WebAPI ASP.NET Core

Dans des questions similaires, avec ce code fonctionne pour télécharger un PDF:

Je teste avec des fichiers locaux (.xlsx, .pdf, .Zip) dans le dossier Controller.

Question similaire ici

[HttpGet("downloadPDF")]
public FileResult TestDownloadPCF()
{
   HttpContext.Response.ContentType = "application/pdf";
   FileContentResult result = new FileContentResult
   (System.IO.File.ReadAllBytes("Controllers/test.pdf"), "application/pdf")
    {
      FileDownloadName = "test.pdf"
    };
   return result;
}

 This works great!

Mais lorsqu'un autre fichier?, Par exemple un fichier Excel (.xlsx) ou un fichier Zip (.Zip), le test ne fonctionne pas correctement.

Code: 

[HttpGet("downloadOtherFile")]
public FileResult TestDownloadOtherFile()
{
  HttpContext.Response.ContentType = 
  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
  FileContentResult result = new FileContentResult(System.IO.File.ReadAllBytes("Controllers/test.xlsx"), 
  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
  {
    FileDownloadName = "otherfile"
   };
  return result;
}

Résultat:  enter image description here

J'ai également fait des tests avec le type de contenu suivant:

  • "Application/vnd.ms-Excel"
  • "Application/vnd.ms-Excel.12"

Obtenir le même résultat.

Quel est le bon moyen de renvoyer n'importe quel type de fichier?

Merci pour vos réponses

Ma solution (de travail):

  • J'ai une classe qui crée dynamiquement un fichier XLSX en utilisant EPPlus.Core .
    • Ceci retourne une FileInfo pour le chemin du fichier généré.

C'est ce qui est dans mon contrôleur:

[HttpGet("test")]
public async Task<FileResult> Get()
{
    var contentRootPath = _hostingEnvironment.ContentRootPath;

    // "items" is a List<T> of DataObjects
    var items = await _mediator.Send(new GetExcelRequest());

    var fileInfo = new ExcelFileCreator(contentRootPath).Execute(items);
    var bytes = System.IO.File.ReadAllBytes(fileInfo.FullName);

    const string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    HttpContext.Response.ContentType = contentType;
    HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");

    var fileContentResult = new FileContentResult(bytes, contentType)
    {
        FileDownloadName = fileInfo.Name
    };

    return fileContentResult;
}

Et voici ce que j'ai dans Angular2:

downloadFile() {
    debugger;
    var headers = new Headers();
    headers.append('responseType', 'arraybuffer');

    let url = new URL('api/excelFile/test', environment.apiUrl);

    return this.http
        .get(url.href, {
            withCredentials: true,
            responseType: ResponseContentType.ArrayBuffer
        })
        .subscribe((response) => {
            let file = new Blob([response.blob()], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
            let fileName = response.headers.get('Content-Disposition').split(';')[1].trim().split('=')[1];
            saveAs(file, fileName);
        },
        err => this.errorHandler.onError(err)
        );
}
4
BCdotWEB

J'ai eu le même problème. Mon problème était causé par la demande du client, pas la réponse du serveur. Je l'ai résolu en ajoutant un type de contenu de réponse aux options d'en-tête de ma requête Get. Voici mon exemple dans Angular 2.

Demande du client (angulaire 2) ** requiert la bibliothèque filesaver.js

this._body = '';

    let rt: ResponseContentType = 2; // This is what I had to add ResponseContentType (2 = ArrayBuffer , Blob = 3)
        options.responseType = rt;
    if (url.substring(0, 4) !== 'http') {
        url = config.getApiUrl(url);
    }

    this.http.get(url, options).subscribe(
        (response: any) => {
            let mediaType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
            let blob = new Blob([response._body], { type: mediaType });
            let filename = 'test.xlsx';
            fileSaver.saveAs(blob, filename);
        });

Code côté serveur. (noyau .net)

    [HttpGet("{dataViewId}")]
    public IActionResult GetData(string dataViewId)
    {
        var fileName = $"test.xlsx";
        var filepath = $"controllers/test/{fileName}";
        var mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

        byte[] fileBytes = System.IO.File.ReadAllBytes(filepath);
        return File(fileBytes, mimeType, fileName);
    }

voici les références si vous voulez voir.

Téléchargement corrompu dans l'application AngularJs

Le téléchargement du fichier C # est corrompu

2
Jay Culpepper

Voici un exemple de téléchargement d’un fichier. Vous pouvez modéliser votre scénario de téléchargement d’un fichier Excel après celui-ci:

public IActionResult Index([FromServices] IHostingEnvironment hostingEnvironment)
{
    var path = Path.Combine(hostingEnvironment.ContentRootPath, "Controllers", "TextFile.txt");
    return File(System.IO.File.OpenRead(path), contentType: "text/plain; charset=utf-8", fileDownloadName: "Readme.txt");
}

Si le fichier se trouve dans le dossier wwwroot, vous pouvez faire quelque chose comme ci-dessous:

public IActionResult Index()
{
    return File(virtualPath: "~/TextFile.txt", contentType: "text/plain; charset=utf-8", fileDownloadName: "Readme.txt");
}
0
Kiran Challa