Dans un contrôleur MVC standard, nous pouvons générer un pdf avec un fichier FileContentResult
.
public FileContentResult Test(TestViewModel vm)
{
var stream = new MemoryStream();
//... add content to the stream.
return File(stream.GetBuffer(), "application/pdf", "test.pdf");
}
Mais comment pouvons-nous le changer en un ApiController
?
[HttpPost]
public IHttpActionResult Test(TestViewModel vm)
{
//...
return Ok(pdfOutput);
}
Voici ce que j'ai essayé mais cela ne semble pas fonctionner.
[HttpGet]
public IHttpActionResult Test()
{
var stream = new MemoryStream();
//...
var content = new StreamContent(stream);
content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
content.Headers.ContentLength = stream.GetBuffer().Length;
return Ok(content);
}
Le résultat renvoyé affiché dans le navigateur est:
{"Headers":[{"Key":"Content-Type","Value":["application/pdf"]},{"Key":"Content-Length","Value":["152844"]}]}
Et il existe un article similaire sur SO: Renvoyer un fichier binaire à partir du contrôleur dans l'API Web ASP.NET . Il parle de la sortie d'un fichier existant. Mais je ne pouvais pas le faire fonctionner avec un flux.
Aucune suggestion?
c#
asp.net
asp.net-mvc
asp.net-web-api
Blaise
la source
la source
Réponses:
Au lieu de revenir en
StreamContent
tant queContent
, je peux le faire fonctionner avecByteArrayContent
.la source
MemoryStream.GetBuffer()
que renvoie en fait le tampon du MemoryStream, qui est généralement plus grand que le contenu du flux (pour rendre les insertions efficaces).MemoryStream.ToArray()
renvoie le tampon tronqué à la taille du contenu.byte[]
tampons à la place? Vos utilisateurs peuvent facilement exécuter votre application à court de mémoire.Si vous souhaitez revenir,
IHttpActionResult
vous pouvez le faire comme ceci:la source
Cette question m'a aidé.
Alors, essayez ceci:
Code contrôleur:
Afficher le balisage HTML (avec événement de clic et URL simple):
la source
FileStream
pour un fichier existant sur le serveur. C'est un peu différent deMemoryStream
. Mais merci pour la contribution.FileStream
mais échoue avecMemoryStream
. Cela a essentiellement à voir avec le StreamPosition
.Voici une implémentation qui diffuse le contenu du fichier sans le mettre en mémoire tampon (la mise en mémoire tampon dans l'octet [] / MemoryStream, etc. peut être un problème de serveur s'il s'agit d'un gros fichier).
Il peut être simplement utilisé comme ceci:
la source
var fs = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose);
place deFile.OpenRead(FilePath)
Je ne sais pas exactement quelle partie blâmer, mais voici pourquoi
MemoryStream
ne fonctionne pas pour vous:Au fur et à mesure que vous écrivez
MemoryStream
, il incrémente saPosition
propriété. Le constructeur deStreamContent
prend en compte le courant du fluxPosition
. Donc, si vous écrivez dans le flux, puis passez-le àStreamContent
, la réponse commencera à partir du néant à la fin du flux.Il y a deux façons de résoudre correctement ce problème:
1) construire du contenu, écrire dans le flux
2) écrire dans le flux, réinitialiser la position, créer du contenu
2) semble un peu mieux si vous avez un nouveau Stream, 1) est plus simple si votre flux ne commence pas à 0
la source
Pour moi, c'était la différence entre
et
Le premier renvoyait la représentation JSON de StringContent: {"Headers": [{"Key": "Content-Type", "Value": ["application / octet-stream; charset = utf-8"]}]}
Alors que le second retournait le fichier proprement dit.
Il semble que Request.CreateResponse a une surcharge qui prend une chaîne comme deuxième paramètre et cela semble avoir été ce qui a provoqué le rendu de l'objet StringContent lui-même sous forme de chaîne, au lieu du contenu réel.
la source