Pdf corrupted in HttpResponseMessage - c#

I have a ASP.NET MVC 5 project in which i am trying to download a pdf. I thought this would be pretty straightforward, but apparently not so, as the pdf somehow gets formatted wrongly when sent to the browser. Chrome will read the pdf, but all special characters and images looks corrupted, and Edge simply refuses to open it.
The pdf file is written in Danish, so it contains letters like 'æ', 'ø' and 'å', and also contains various images.
I've simplified my code current code, but the issue is still the same:
[HttpGet]
public HttpResponseMessage DownloadDocument()
{
try
{
var localFilePath = "C:\\*somepath*\\Testpdf.pdf";
var fileStream = new FileStream(localFilePath, FileMode.Open, FileAccess.Read);
fileStream.Seek(0, SeekOrigin.Begin);
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(fileStream);
response.Content.Headers.Add("Content-Disposition", "inline;filename=\"Testpdf.pdf\"");
response.Content.Headers.Add("Content-Length", fileStream.Length.ToString());
response.Content.Headers.Add("Content-Name", "Testpdf.PDF");
response.Content.Headers.Add("Content-Type", "application/pdf;charset=UTF-8");
return response;
}
catch (Exception e)
{
throw e;
}
}
It reads a pdf from the disk and assigns the filestream to the content of the HttpResponseMessage. In the example I'm using a StreamContent, but the result is still the same if switch to ByteArrayContent.
I've also tried writing the file back onto the disk, with no issues at all. I've litterally just done the same behaviour in a dotnetcore 2.0 web project, with no issues what-so-ever, which leads me to believe that the formatters in of the Web API is parsing the content wrong.
I'm at my wits end here, so any input would be much appreciated.

I fixed this issue by removing the jwt "Authorization" token from the Request Headers. I changed it to get the token from the url instead, by making a alternate provider, following this article:
https://leastprivilege.com/2013/10/31/retrieving-bearer-tokens-from-alternative-locations-in-katanaowin/

Related

How to make a download file response in .net core?

I'm using endpoints.Map("/{*name}", RequestDelegate) method to make a download file API.
In the RequestDelegate handler method, I'm using await context.Response.SendFileAsync(IFileInfo) method to return the file.
Then, I request this API in browser, but the browser did not download it, instead of showing the file content in browser directly. What's missing from my code. I want the browser to download the file.
await context.Response.SendFileAsync(GetFile(val));
private IFileInfo GetFile(string file_name)
{
string downloadPath = Configuration.GetSection("DownloadFilePath").Get<string>();
IFileProvider provider = new PhysicalFileProvider(AppDomain.CurrentDomain.BaseDirectory);
IFileInfo fileInfo = provider.GetFileInfo($"{downloadPath}/{file_name}");
return fileInfo;
}
There are few things to consider:
Browser now a days detect the file and try to handle them themselves like PDF, Txt file since they can open those file they show the content instead of downloading.
To make the download it is important to ensure you send proper HTML Header, and make Content-Disposition (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) to tell and force browser to act to your will.
If you are using HTML A tag for your file you can use download attribute to tell the same thing. But I am not sure if it is fully supported.
In your code, I see you do not send header of any kind. it is good idea to set cache expiry, Disposition, Content-Type of file (since it is dynamic system will probably send default content type which can cause confusion to client side tools. ) and content-length. these are important header to send to make your code work properly.
I am not sure how to answer it properly for technical documentation purpose, but those are steps I guide to my team for when they write same code.
EDIT:
Those points are Programming language independent but on web architecture (HTTP standards).
I figured it out. I need to add the response headers for it.
var fileinfo = GetFile(val);
context.Response.Clear();
context.Response.Headers.Add("Content-Disposition", "attachment;filename=" + fileinfo.Name);
context.Response.Headers.Add("Content-Length", fileinfo.Length.ToString());
context.Response.Headers.Add("Content-Transfer-Encoding", "binary");
new FileExtensionContentTypeProvider().Mappings.TryGetValue(fileinfo.Extension, out var contenttype);
context.Response.ContentType = contenttype ?? "application/octet-stream";
await context.Response.SendFileAsync(fileinfo.FullName);
private FileInfo GetFile(string file_name)
{
string downloadPath = Configuration.GetSection("DownloadFilePath").Get<string>();
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, downloadPath, file_name);
FileInfo fileInfo = new FileInfo(path);
return fileInfo;
}

.net core web api File randomly loads only part of the response

I am loading an image from S3 bucket as byte[] and send it as a response from my asp.net core 3.1 web API controller method.
Here is my code:
public async Task<IActionResult> GetImage(string documentId, int pageId)
{
var imageArray = await _documentService.GetImage(documentId, pageId);
return File(imageArray, "image/png");
}
It works to an extend. The Response is delivered to the client:
But the image itself is never fully loaded:
sometimes it loads just a little bit:
sometimes a bit more:
But never the full image. Looks like it interrupts for whatever reason and just sends whatever got into the initial buffer.
Thanks to #Athanasios - the issue is not related to the File response.
I wasn't reading the S3 stream properly. The error has gone after fixing it.

Why does WebClient.UploadValues overwrites my html web page?

I'm familiar with Winform and WPF, but new to web developing. One day saw WebClient.UploadValues and decided to try it.
static void Main(string[] args)
{
using (var client = new WebClient())
{
var values = new NameValueCollection();
values["thing1"] = "hello";
values["thing2"] = "world";
//A single file that contains plain html
var response = client.UploadValues("D:\\page.html", values);
var responseString = Encoding.Default.GetString(response);
Console.WriteLine(responseString);
}
Console.ReadLine();
}
After run, nothing printed, and the html file content becomes like this:
thing1=hello&thing2=world
Could anyone explain it, thanks!
The UploadValues method is intended to be used with the HTTP protocol. This means that you need to host your html on a web server and make the request like that:
var response = client.UploadValues("http://some_server/page.html", values);
In this case the method will send the values to the server by using application/x-www-form-urlencoded encoding and it will return the response from the HTTP request.
I have never used the UploadValues with a local file and the documentation doesn't seem to mention anything about it. They only mention HTTP or FTP protocols. So I suppose that this is some side effect when using it with a local file -> it simply overwrites the contents of this file with the payload that is being sent.
You are using WebClient not as it was intended.
The purpose of WebClient.UploadValues is to upload the specified name/value collection to the resource identified by the specified URI.
But it should not be some local file on your disk, but instead it should be some web-service listening for requests and issuing responces.

Web API issue with sending compressed response

I have been working on getting gzip/deflate compression working on Web API responses. I have been using the code from Github - MessageHandlers.Compression. However it didn't appear to work. There was no Content-Encoding header appearing in the Google Developer console or in Firebug in Firefox and the Content-Length was consistently set to the uncompressed size of the data. So I kept stripping out the code until I ended up with the following:
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// Send the request to the web api controller
var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
// Compress uncompressed responses from the server
if (response.Content != null && request.Headers.AcceptEncoding.IsNotNullOrEmpty())
{
var content = response.Content;
var bytes = content.ReadAsByteArrayAsync().Result;
if (bytes != null && bytes.Length > 1024)
{
// The data has already been serialised to JSon by this point
var compressedBytes = Compress(bytes);
response.Content = new ByteArrayContent(compressedBytes);
var headers = response.Content.Headers;
headers.Remove("Content-Type");
headers.ContentLength = compressedBytes.Length;
headers.ContentEncoding.Clear();
headers.ContentEncoding.Add("gzip");
headers.Add("Content-Type", "application/json");
}
}
return response;
}
private static byte[] Compress(byte[] input)
{
using (var compressStream = new MemoryStream())
{
using (var compressor = new GZipStream(compressStream, CompressionMode.Compress))
{
compressor.Write(input, 0, input.Length);
compressor.Close();
return compressStream.ToArray();
}
}
}
When I initially did this I made a mistake, and set the content encoding in the header to 'gzip' when I used a DeflateStream in the Compress method. As you would expect I got an error in the browser, however the response headers were correct(!). That is, the Content-Encoding header was set and the Content-Length was correct. As well, looking at the raw data I could clearly see if was compressed. As soon as I corrected my error though the problem returned.
What I am wondering is do the latest versions of the browser decompress the content behind the scenes, or is there actually something wrong with my code? Responses are sent in Json format
Any help much appreciated.
EDIT
I tried dumping the headers to a log file in the following methods in Global.asax (listed in the order they appeared in the log):
Application_PreSendRequestHeaders
Application_EndRequest
Application_PreSendRequestContent
In each case the required headers were there, even though they didn't appear in the Google developer console. I then took a look at the solution at Code Project. When run from the command line everything worked as anticipated. However when I called the web server from Google Chrome I got the exact same result. That is, no Content-Encoding header, and no indication as to whether the content had been compressed or not. However with the developer console open it's easy to see this header at other sites (stack overflow for instance). I have to assume this is therefore something to do with compressed responses from web api services. It's so hard to know though if this is actually working client side.
In case anyone doesn't want to read all the comments the answer came from Jerry Hewett (jerhewet). Namely that anti-virus software intercepts the response before it gets to the browser. The anti-virus software decompresses the data, no doubt as part of the scanning process. Huge thanks to Jerry for his help here.

How to accept xml file in via http post method and parse request headers.?

I am sending Xml file from web broser rest client. I need to accept xml file in asp.net web api http post method.
How do I get xml file content , its file name and headers content from asp.net web api http post method.?
I referred a few msdn links such as http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2 , i did not get this tutorial
somehow i wrote code
HttpRequestMessage request = this.Request;
var task = this.Request.Content.ReadAsStreamAsync();
task.Wait();
Stream requestStream = task.Result;
string inp = request.Content.ReadAsStringAsync().Result;
string result = await request.Content.ReadAsStringAsync();
try
{
Stream fileStream = File.Create(#"c:\\test\\1.xml");
requestStream.CopyTo(fileStream);
fileStream.Close();
requestStream.Close();
}
catch (IOException)
{
throw new HttpResponseException("A generic error occured. Please try again later.", HttpStatusCode.InternalServerError);
}
through this above code i don't get full xml content.
I am completely new to asp.net web api and .net framework.
Please provide procedure to implement this and code.
If you are posting the XML file via File Upload, then this link at www.asp.net should help. Otherwise, if you are simply posting a string then you shouldn't need to do anything special other than supply a string parameter in your controller method to receive the XML string (in which case Web API will automagically do the mapping for you).

Categories