'How to return a file using Web API?
I am using ASP.NET Web API.
I want to download a PDF with C# from the API (that the API generates).
Can I just have the API return a byte[]
? and for the C# application can I just do:
byte[] pdf = client.DownloadData("urlToAPI");?
and
File.WriteAllBytes()?
Solution 1:[1]
Better to return HttpResponseMessage with StreamContent inside of it.
Here is example:
public HttpResponseMessage GetFile(string id)
{
if (String.IsNullOrEmpty(id))
return Request.CreateResponse(HttpStatusCode.BadRequest);
string fileName;
string localFilePath;
int fileSize;
localFilePath = getFileFromID(id, out fileName, out fileSize);
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read));
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = fileName;
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return response;
}
UPDATE from comment by patridge:
Should anyone else get here looking to send out a response from a byte array instead of an actual file, you're going to want to use new ByteArrayContent(someData)
instead of StreamContent
(see here).
Solution 2:[2]
I made the follow action:
[HttpGet]
[Route("api/DownloadPdfFile/{id}")]
public HttpResponseMessage DownloadPdfFile(long id)
{
HttpResponseMessage result = null;
try
{
SQL.File file = db.Files.Where(b => b.ID == id).SingleOrDefault();
if (file == null)
{
result = Request.CreateResponse(HttpStatusCode.Gone);
}
else
{
// sendo file to client
byte[] bytes = Convert.FromBase64String(file.pdfBase64);
result = Request.CreateResponse(HttpStatusCode.OK);
result.Content = new ByteArrayContent(bytes);
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = file.name + ".pdf";
}
return result;
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.Gone);
}
}
Solution 3:[3]
Just a note for .Net Core
: We can use the FileContentResult
and set the contentType to application/octet-stream
if we want to send the raw bytes. Example:
[HttpGet("{id}")]
public IActionResult GetDocumentBytes(int id)
{
byte[] byteArray = GetDocumentByteArray(id);
return new FileContentResult(byteArray, "application/octet-stream");
}
Solution 4:[4]
Example with IHttpActionResult
in ApiController
.
[HttpGet]
[Route("file/{id}/")]
public IHttpActionResult GetFileForCustomer(int id)
{
if (id == 0)
return BadRequest();
var file = GetFile(id);
IHttpActionResult response;
HttpResponseMessage responseMsg = new HttpResponseMessage(HttpStatusCode.OK);
responseMsg.Content = new ByteArrayContent(file.SomeData);
responseMsg.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
responseMsg.Content.Headers.ContentDisposition.FileName = file.FileName;
responseMsg.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
response = ResponseMessage(responseMsg);
return response;
}
If you don't want to download the PDF and use a browsers built in PDF viewer instead remove the following two lines:
responseMsg.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
responseMsg.Content.Headers.ContentDisposition.FileName = file.FileName;
Solution 5:[5]
I've been wondering if there was a simple way to download a file in a more ... "generic" way. I came up with this.
It's a simple ActionResult
that will allow you to download a file from a controller call that returns an IHttpActionResult
.
The file is stored in the byte[] Content
. You can turn it into a stream if needs be.
I used this to return files stored in a database's varbinary column.
public class FileHttpActionResult : IHttpActionResult
{
public HttpRequestMessage Request { get; set; }
public string FileName { get; set; }
public string MediaType { get; set; }
public HttpStatusCode StatusCode { get; set; }
public byte[] Content { get; set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response = new HttpResponseMessage(StatusCode);
response.StatusCode = StatusCode;
response.Content = new StreamContent(new MemoryStream(Content));
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = FileName;
response.Content.Headers.ContentType = new MediaTypeHeaderValue(MediaType);
return Task.FromResult(response);
}
}
Solution 6:[6]
You Can try , HttpClient for Download file from another side and same time you can pass as File Result
[HttpGet]
[Route("api/getFile")]
public async Task<FileResult> GetFile(string Param1,string Param2)
{
try
{
Stream stream = null;
string strURL = @"File URL";
HttpClient client = new HttpClient();
HttpResponseMessage httpResponse = await client.GetAsync(strURL);
Stream streamToReadFrom = await httpResponse.Content.ReadAsStreamAsync();
return File(streamToReadFrom, "{MIME TYPE}");
}
catch (Exception ex)
{
throw ex;
}
finally
{
}
}
Solution 7:[7]
Another way to download file is to write the stream content to the response's body directly:
[HttpGet("pdfstream/{id}")]
public async Task GetFile(long id)
{
var stream = GetStream(id);
Response.StatusCode = (int)HttpStatusCode.OK;
Response.Headers.Add( HeaderNames.ContentDisposition, $"attachment; filename=\"{Guid.NewGuid()}.pdf\"" );
Response.Headers.Add( HeaderNames.ContentType, "application/pdf" );
await stream.CopyToAsync(Response.Body);
await Response.Body.FlushAsync();
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | ZAD-Man |
Solution 2 | Hakan Fıstık |
Solution 3 | |
Solution 4 | |
Solution 5 | |
Solution 6 | Sachin Bali |
Solution 7 | Adam Moszczy?ski |