Laden...

Word download von Web API

Erstellt von dila71 vor 4 Jahren Letzter Beitrag vor 4 Jahren 985 Views
D
dila71 Themenstarter:in
103 Beiträge seit 2005
vor 4 Jahren
Word download von Web API

Hallo,
Was will ich: Ich will Daten an einen C# Webservice übergeben, ein Word als MemoryStream erzeugen und ausliefern.
Was habe ich: Alles bis auf das Ausliefern.
Was ist mein Problem?
Ich habe 2 Lösungsansätze versucht.

  1. Ansatz
    Wie unter https://www.c-sharpcorner.com/article/sending-files-from-web-api/ beschrieben, habe ich mir (statt der dort verwendeten class eBookResult) eine Klasse WordResult geschrieben.

public class WordResult : IHttpActionResult
{
    readonly MemoryStream _wordContent;
    readonly string _wordFileName;
    readonly HttpRequestMessage _httpRequestMessage;

    public WordResult(MemoryStream data, HttpRequestMessage request, string filename)
    {
        _wordContent = data;
        _httpRequestMessage = request;
        _wordFileName = filename;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        _wordContent.Position = 0;
        var httpResponseMessage = _httpRequestMessage.CreateResponse(HttpStatusCode.OK);
        httpResponseMessage.Content = new StreamContent(_wordContent);
        httpResponseMessage.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment") { FileName = _wordFileName };
        httpResponseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        return Task.FromResult(httpResponseMessage);
    }
}

Wird verwendet in meiner API-Methode:


[HttpPost]
public async Task<IHttpActionResult> CalculateAndExport([NotNull] EvaluationExportParameters parameters)
{
     //hier die Worderzugung als MemoryStream dataStream
     return new WordResult(dataStream, Request, "DocumentName.docx");
}

Ergebnis: Wenn ich den Service über swagger aufrufe, bekomme ich eine Worddatei zum Download angeboten, Word sagt mir jedoch, dass die Datei beschädigt sei.
Füge ich an den Anfang der ExecuteAsync Methode


_wordContent.Position = 0;
using (var file = new FileStream(_wordFileName, FileMode.Create, System.IO.FileAccess.Write))
    _wordContent.CopyTo(file);

ein, bekomme ich in meinem bin/Debug Verzeichnis eine Datei welche ich öffnen kann und die auch den richtigen Inhalt hat.
Unterschied, die Datei im bin/Debug Verzeichnis ist 45Kb, die im Download 77Kb.

  1. Ansatz:
    Wie unter https://iditect.com/faq/pdf/pdf-document-to-webapi-for-download.html unter Answer für ein Pdf beschrieben, wäre meine API-Methode:

[HttpPost]
public async Task<IHttpActionResult> CalculateAndExport([NotNull] EvaluationExportParameters parameters)
{
    //hier die Worderzugung als MemoryStream dataStream

    var content = new StreamContent(dataStream);
    content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") {FileName = "DocumentName.docx"};
    content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
    content.Headers.ContentLength = dataStream.GetBuffer().Length;
    return Ok(content);
}

Ergebnis:
statt eines downloadbaren Files bekomme ich als Response nur ein JSON Konstrukt:


{
  "Headers": [
    {
      "Key": "Content-Disposition",
      "Value": [
        "attachment; filename=Stellungnahme.docx"
      ]
    },
    {
      "Key": "Content-Type",
      "Value": [
        "application/octet-stream"
      ]
    },
    {
      "Key": "Content-Length",
      "Value": [
        "48468"
      ]
    }
  ]
}

Kann mir wer auf die Sprünge helfen, wo ich mich zu blöd anstelle?
Ist einer der beiden Ansätze überhaupt zielführend?

Vielen Dank
Dila

16.842 Beiträge seit 2008
vor 4 Jahren

Das Vorgehen über Ok() kann nicht funktionieren, denn wie Du der Doku entnehmen kannst gibst das eben (per default) Json zurück.
Das ist auch Quatsch das zu verändern.

Der Weg über das eigene Result ist prinzipiell der korrekte, empfohlene Weg; alternativ über File().
Wenn die Datei beschädigt ist, dann ist eben ein Bug drin; vermutlich darfst Du nicht den Quellstream direkt verwenden, sondern musst kopieren.
Musst mal debuggen, was Du erwartest und was drin ist.

Edit: für Standarddateien wie Word, PDF und Co sollte File() völlig reichen, sofern das Standardverhalten von File() ok ist.

D
dila71 Themenstarter:in
103 Beiträge seit 2005
vor 4 Jahren

Hallo Abt,
vielen Dank für Deine Antwort.

Diese hat mich dazu gebracht den Fehler nicht bei mir zu suchen und siehe da, die eigene Responseklasse funktioniert.

Das Problem war, dass ich das Ganze über eine durch eine Bibliothek erstellte Swagger-Doku getestet habe. Diese speichert das Ganze zwischen und wenn man dann von dort die Datei lädt und speichert kommt Mist raus.
Den Webservice direkt ansprechen und das Ergebnis speichern funktioniert prima.

Falls mal wer nach ner Lösung sucht, obiges funktioniert.