What is the alternative for HttpContext.Response.OutputStream to use in WebAPI's HttpResponseMessage - asp.net-web-api

I'm writing a WebAPI for handling PDF documents. It was written in a ashx page earlier implementing IHttpHandler and getting the context using HttpContext. I'm now writing it using WebAPI. In WebAPI we have HttpResponseMessage. For HttpContext.Response.BinaryWrite we have new ByteArrayContent in HttpResponseMessage. But what is the alternative for HttpContext.Response.OutputStream in WebAPI? I need to have the alternative of OutputStram in WebAPI because im passing this OutputStream as a parameter to another dll.
Code in ashx:
SomeReport.PdfReport rpt = new SomeReport.PdfReport(docID);
rpt.CreateReport(context.Response.OutputStream);

Actually you can use any stream for example MemoryStream but result should be wrapped into StreamContent.
public HttpResponseMessage Get()
{
var response = Request.CreateResponse();
var outputStream = new MemoryStream();
//write data to output stream
//or passing it to somewhere
outputStream.WriteByte(83);
outputStream.Position = 0;
response.Content = new StreamContent(outputStream);
return response;
}
If you need direct writing to output stream, please consider using PushStreamContent. Example

Related

How to download file using IHttpClientFactory in .Net Core 2.2?

In my web application (.net Core 2.2) I want to add the functionality of downloading a PDF file.
When the user clicks "download" - POST is sent to WebAPI and the server ask different server for PDF file by hardcoded URL (invisible to the user) and the file is passed to the user.
I was trying to use IHttpClientFactory
Startup:
services.AddHttpClient("demo", c =>
{
c.BaseAddress = new Uri("http://www.africau.edu/");
c.DefaultRequestHeaders.Add("Accept", "application/pdf");
});
Method for returns PDF file:
public async Task<FileStreamResult> GetPdfFile()
{
var client = _httpClientFactory.CreateClient("demo");
var uri = new UriBuilder(client.BaseAddress + "images/default/sample.pdf").Uri;
var stream = await client.GetStreamAsync(uri);
return new FileStreamResult(stream, new MediaTypeHeaderValue("application/pdf"));
}
Unfortunately it returns file download.json with: {"fileStream":{"needsDrain":true,"canRead":true,"canWrite":false,"canSeek":false
#EDIT
it seems that it's because I had Task<IActionResult> in my Controller instead of Task<FileStreamResult> but what if i prefer to returns ActionResult?
public async Task<IActionResult> GetPdf()
{
var result = await _service.GetPdfFile();
return Ok(result);
}
In your GetPdf method, you're passing a FileStreamResult to the Ok() method. This will serialize the FileStreamResult using the default serializer and send it to the client, hence why you're seeing the JSON.
Usually your service layer should not return an MVC WhateverResult object but rather an object intended to represent the actual data being retrieved - in your case this would be a PDF file. The easiest way to solve your particular case would probably be to do the following:
change GetPdfFile to return Task<FileStream> instead of Task<FileStreamResult>
remember to change its return statement to return stream;
change the return statement of GetPdf to return File(result, "application/pdf");
This will allow your service layer to return the PDF file as a stream, and then have your GetPdf endpoint return that stream as a file with the application/pdf file type.

Web API - Setting Response.Content with byte[] / MemoryStream Contents not working properly

My requirement is to use Web API to send across the network, a zip file (consisting a bunch of files in turn) which should not be written anywhere locally (not written anywhere on the server/client disk). For zipping, I am using DotNetZip - Ionic.Zip.dll
Code at Server:
public async Task<IHttpActionResult> GenerateZip(Dictionary<string, StringBuilder> fileList)
{
// fileList is actually a dictionary of “FileName”,”FileContent”
byte[] data;
using (ZipFile zip = new ZipFile())
{
foreach (var item in filelist.ToArray())
{
zip.AddEntry(item.Key, item.Value.ToString());
}
using (MemoryStream ms = new MemoryStream())
{
zip.Save(ms);
data = ms.ToArray();
}
}
var result = new HttpResponseMessage(HttpStatusCode.OK);
MemoryStream streams = new MemoryStream(data);
//, 0, data.Length-1, true, false);
streams.Position = 0;
//Encoding UTFEncode = new UTF8Encoding();
//string res = UTFEncode.GetString(data);
//result.Content = new StringContent(res, Encoding.UTF8, "application/zip");
<result.Content = new StreamContent(streams);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/zip");
//result.Content.Headers.ContentLength = data.Length;
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = "test.zip";
return this.Ok(result);
}
The issue I am facing is that after the zip file downloaded at client end when modified as a test.bin has its stream contents (byte[] data in this example’s contents) missing. (I am getting back a test.zip file. When I change the file locally from test.zip to test.bin, I am seeing that the File’s contents as shown below. It does not contain the Response.Content values. P.S. I have also tried the MIME type “application/octet-stream” as well. No luck!)
Test.zip aka test.bin’s contents:
{"version":{"major":1,"minor":1,"build":-1,"revision":-1,"majorRevision":-1,"minorRevision":-1},
"content":{"headers":[{"key":"Content-Type","value":["application/zip"]},
{"key":"Content-Disposition","value":["attachment; filename=test.zip"]}]},
"statusCode":200,"reasonPhrase":"OK","headers":[],"isSuccessStatusCode":true}
Can someone please help me on how we can set result.Content with a MemoryStream object (I have seen example of “FileStream” at other places on google to set “result.Content” but I want to use MemoryStream object only!). I am highlighting this because I think the problem lies with setting the MemoryStream object to the result.Content (in order to properly save the streams content into the result.Content object)
P.S. I have also gone thru Uploading/Downloading Byte Arrays with AngularJS and ASP.NET Web API (and a bunch of other links) but it did not help me much… :(
Any help is greatly appreciated. Thanks a lot in advance :)
I got my issue solved!!
All I did was to change the Response Type to HttpResponseMessage and use "return result" in the last line rather than Ok(result) { i.e. HttpResponseMessage Type rather than OKNegiotatedContentResult Type)

Globally formatting .net Web Api response

I have a Web Api service that retrieves data from another service, which returns Json. I don't want to do anything to the response, I just want to return it directly to the client.
Since the response is a string, if I simply return the response, it contains escape characters and messy formatting. If I convert the response in to an object, the WebApi will use Json.Net to automatically format the response correctly.
public IHttpActionResult GetServices()
{
var data = _dataService.Get(); //retrieves data from a service
var result = JsonConvert.DeserializeObject(data); //convert to object
return Ok(result);
}
What I would like is to either A: Be able to return the exact string response from the service, without any of the escape characters and with the proper formatting, or B: Set a global settings that will automatically Deserialize the response so that the Web Api can handle it the way I am doing it already.
On Startup I am setting some values that describe how formatting should be handled, but apparently these aren't correct for what im trying to do.
HttpConfiguration configuration = new HttpConfiguration();
var settings = configuration.Formatters.JsonFormatter.SerializerSettings;
settings.Formatting = Formatting.Indented;
settings.ContractResolver = new DefaultContractResolver();
Do I need to create a custom ContractResolver or something? Is there one that already handles this for me?
Thanks
If you want to just pass through the json (Option A), you can do this
public IHttpActionResult GetServices() {
var json = _dataService.Get(); //retrieves data from a service
HttpContent content = new System.Net.Http.StringContent(json, Encoding.UTF8, "application/json");
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = content;
return ResponseMessage(response);
}

Read both key values and files from multipart from data post request in ASP.NET WebAPI

I have an endpoint that needs to accept a file upload and also some other information from the client request. With the following code I can upload the file successfully but can't seem to figure out how to read the other info.
I make a test request from Postman with the following form data:
image -- myimage.jpg -- of type File
email -- a#b.com -- of type Text
The backend code looks like this:
[HttpPost]
public async Task<HttpResponseMessage> SharePhoto()
{
try
{
var provider = new MultipartMemoryStreamProvider();
var data = await Request.Content.ReadAsMultipartAsync(provider);
// this is how I get the image which I am succesfully passing to EmailService
var item = (StreamContent)provider.Contents[0];
using (var stream = new MemoryStream())
{
await item.CopyToAsync(stream);
String emailAddress;
EmailService.SendSharedPhoto(emailAddress, stream);
return Request.CreateResponse();
}
}
catch
{
// do stuff
}
}
In this example I am able to access provider.Contents[1] but can't seem to be able to get the value from it into emailAddress. I'm thinking it may be possible to use the same trick as the await item.CopyToASync(stream) from the image upload, but I'm hoping I can get a simpler solution to that. Any ideas?
I just barely answered a very similar question to this yesterday. See my answer here complete with sample controller code.
The method I ended up using is:
If the form elements are strings (and it worked for me since the mobiel frontend took responsability for input data) you can do this:
var streamContent = (StreamContent)provider.Contents[1];
var memStream = new MemoryStream();
await streamContent.CopyToAsync(memStream);
var actualString = Encoding.UTF8.GetString(x.ToArray());
If however the field needs to represent a collection of items, like for example the email list: ["a#b.com", "x#c.com"], etc a JavaScriptSerializer can be user, like so:
var streamContent = (StreamContent)provider.Contents[1];
var emailAddresses = await str.ReadAsStringAsync();
var jsSerializer = new JavaScriptSerializer();
var deserializedData = jsSerializer.Deserialize<string[]>(emailAddresses);
Note that this is nowhere near safe, though it is few lines of code and happens to work.

MVC. Itextsharp write pdf to response

I am generating pdf using itexsharp.
I am creating MemoryStream, then when i am trying t write MemoryStream bytes in to response but no luck. When i am executing this code in my controller the pdf not coming in response. Memory stream is populaitng correctly i can see this in debugger, but for some reason this number of butes not coming in response.
Here is my code:
HttpContext.Current.Response.ContentType = "application/pdf";
...
using (Stream inputPdfStream = new FileStream(pdfFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
using (Stream outputPdfStream = new MemoryStream())
{
PdfReader reader = new PdfReader(inputPdfStream);
PdfStamper stamper = new PdfStamper(reader, outputPdfStream);
....
//try one
outputPdfStream.WriteTo(HttpContext.Current.Response.OutputStream); // NOT POPULATING Response
//try two
HttpContext.Current.Response.BinaryWrite(outputPdfStream.ToArray()); // NOT POPULATING Response Too
HttpContext.Current.Response.End();
}
May be some one have any ideas?
Could you not use
Response.ContentType = "application/pdf"
Response.AddHeader("Content-Type", "application/pdf")
Response.WriteFile(pdfFilePath)
Response.End()
You should use the FileContentResult Controller.File(byte[] content, string contentType) method:
public ActionResult GeneratePDF()
{
var outputStream = new MemoryStream(); // This will hold the pdf you want to send in the response
/*
* ... code here to create the pdf in the outputStrem
*/
return File(outputStream.ToArray(), "application/pdf");
}
Source: Building PDFs in Asp.Net MVC 2.
Probably the memorystream is still set at the position after the last written byte. It will write all bytes from the current position (which is none). If you do a outputPdfStream.Seek(0) it will set the position back to the first byte, and will write the contents of the whole stream to the response output.
Anyway, like Dean says, you should just use the Reponse.WriteFile method.

Resources