Download XML file with Asp.Net MVC - c#

I've created an ActionResult in an MVC controller which returns a FileStreamResult of an XMLfile, but it's not downloading the file.
After the action returns the FileStream nothing happens; I'd like to make the user download the file from the web application.
Any help?
Thanks
public ActionResult EsportaProtocollo(int idProtocollo)
{
AvvisoModel avviso = new AvvisoModel();
string xml = _protocolliService.ProtocolloToXml(idProtocollo);
var newStream = new System.IO.MemoryStream();
var writer = new System.IO.StreamWriter(newStream);
writer.Write(xml);
writer.Flush();
newStream.Position = 0;
return File(newStream, "application/xml", "prova.xml");
}
Here's what I see on Fiddler

Solved! the problem was the javascript, i was calling the action with an ajax call, i've changed it to a window.open(url); and now it works!

Related

How to save the response in the Postman same as the name I mentioned it?

This piece of code will put all the data(string) as an XML format in the Postman. But when I try to save the response in the Postman so, it will save as response.xml, which I don't want. I want that Postman will save my XML content in the form of filename.xml.
So, how should I proceed with? I have to google it and found that something like attachment, content-type, and all must be used. But, didn't solve my case. Please help with your suggestion.
For simplicity, I have reduced the code. Here, graphics is string datatype.
public ActionResult GetXML()
{
string filename = "Demo";
return Content(graphics, "application/xml");
}
You need to set Content-Disposition header so the that browser prompts for saving response.
You can do that by using following approach.
public IActionResult Getxml()
{
var xmlData =
"<records><record><Name>Camacho, Sydnee Q.</Name><Id>1</Id><Age>19</Age><City>Podolsk</City></record><record><Name>Bowman, Lester V.</Name><Id>2</Id><Age>21</Age><City>Padang</City></record></records>";
//sampleFile.xml can be replaced by any filename of your choice.
var fileName = "sampleFile.xml";
Response.Headers.Add("Content-Disposition", $"attachment; filename={fileName}");
return Content(xmlData, "application/xml", Encoding.UTF8);
}
With this change when this URL is browsed in the browser it will prompt save dialog with sampleFile.xml populated as filename.
Also when you save the response from postman it will show sampleFile.xml populated as file name in the dialog.
I hope this will help you solve your issue.
I would suggest to use the FileContentResult for a file download.
public ActionResult GetXML()
{
var fileName = "Demo.xml";
var xml = "...";
return new FileContentResult(Encoding.UTF8.GetBytes(xml), "application/xml; charset=utf-8")
{
FileDownloadName = fileName,
};
}
You need to set the response headers so that the download client automatically treats the content as a "file", the key is the ContentDisposition header, this is how we pass the filename back.
public HttpResponseMessage GetXMLFile()
{
string filename = "Demo";
var byteArray = System.Text.Encoding.UTF8.GetBytes(graphics);
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(new MemoryStream(byteArray), byteArray.Length)
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") //attachment will force download
{
FileName = filename
};
return result;
}

How to pass a pdf from WebAPI and read the pdf from the MVC Controller?

I have a Web API service that should return a PDF.
I am then trying to call that WebAPI method to read the PDF.
Here is my API Method:
[HttpPost]
[Route("GetTestPDF")]
public HttpResponseMessage TestPDF()
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(new FileStream(#"C:\MyPath\MyFile.pdf", FileMode.Open, FileAccess.Read));
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = "MyFile.pdf";
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
return Request.CreateResponse(HttpStatusCode.OK, response);
}
However when I go to read the response I don't see the pdf contents. I am not sure where I am going wrong with this.
Controller Method:
public ActionResult GetPDF()
{
var response = new HttpResponseMessage();
using (HttpClient httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(#"my local host");
response = httpClient.PostAsync(#"api/job/GetTestPDF", new StringContent(string.Empty)).Result;
}
var whatisThis = response.Content.ReadAsStringAsync().Result;
return new FileContentResult(Convert.FromBase64String(response.Content.ReadAsStringAsync().Result), "application/pdf");
}
When I examine whatisThis variable I see the content type and the content dispostion correctly set from my API. However I don't see the content of the PDF.
How can I read the PDF content?
EDIT:
If I read the content as a string in my MVC site I see. (I don't see the actual content of the file)
{"Version":{"_Major":1,"_Minor":1,"_Build":-1,"_Revision":-1},"Content":{"Headers":[{"Key":"Content-Disposition","Value":["attachment; filename=MyFile.pdf"]},{"Key":"Content-Type","Value":["application/pdf"]}]},"StatusCode":200,"ReasonPhrase":"OK","Headers":[],"RequestMessage":null,"IsSuccessStatusCode":true}
I stepped through the WebAPI and it is successfully reading and setting the response.Content with the file contents.
Still not sure if this is an issue on the WebAPI side or the MVC side.
I'll post this initially as an answer because it's easier to format code!
I made an API endpoint to return a PDF file, and if I call it from a browser the file opens as expected.
As your API doesn't appear to do this, let's assume that the problem is there, and hence this.
Here is the endpoint code, that is very similar to yours, but missing the ContentDisposition stuff:
public HttpResponseMessage Get()
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
FileStream fileStream = File.OpenRead("FileName.pdf");
response.Content = new StreamContent(fileStream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return response;
}

Prevent IDM from downloading automatically in web api

I have a web api method that returns an HttpResponseMessage containing a PDF file. The method looks something like this:
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StreamContent(new FileStream(path, FileMode.Open, FileAccess.Read));
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = fileName;
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return response;
When I call this api from client (which is written in angularJS), the Internet Download Manager automatically catches the PDF file and wants to download it. And because I have a security plan for my project, the IDM automatically requests username and password.
Does anyone have an idea about how I'm supposed to programmatically stop IDM from catching the PDF file?
Update: Here's my angularJS code:
$http.post(url, { transactionId: txId }
, {responseType: 'arraybuffer'})
.success(function (response) {
var reader = new FileReader();
var file = new Blob([response.data], {type: 'application/pdf'});
reader.onload = function (e) {
var printElem = angular.element('#printPdfLink');
printElem.attr('target', '_blank');
printElem.attr('href', reader.result);
printElem.attr('ng-click', '');
};
reader.readAsDataURL(file);
})
.error(function (error) {});
Change the mime type to application/octet-stream as a way to work around your problem. Make sure that the file name includes a proper file extension so that it can be recognized by the client system once downloaded.
Another issue is the attachment disposition of the content which typically forces it to save it as a file download. Change it to inline so that the client can consume it without IDM trying to download it as an attachment.
FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read);
StreamContent content new StreamContent(stream);
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline");
content.Headers.ContentDisposition.FileName = fileName;
content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = content;
return response;
I have try to use HttpResponseMessage.
If I use ContentDisposition is inline then response break the file. If use attachment then IDM can detect it.
At the end of the day, I found Accept-Ranges header can make download without IDM but it not valid in HttpResponseMessage.
You can try out my code below to make download file without IDM:
[HttpGet]
[Route("~/download/{filename}")]
public void Download(string filename)
{
// TODO lookup file path by {filename}
// If you want to have "." in {filename} you need enable in webconfig
string filePath = "<path>"; // your file path here
byte[] fileBytes = File.ReadAllBytes(filePath);
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.AddHeader("Accept-Ranges", "bytes");
HttpContext.Current.Response.ContentType = "application/octet-stream";
HttpContext.Current.Response.AddHeader("ContentDisposition", "attachment, filename=" + filename);
HttpContext.Current.Response.BinaryWrite(fileBytes);
HttpContext.Current.Response.End();
}
Note: filename parameter serve for download file name so you can config in webconfig if you want to have file extension (disabled by default).

download xlsx as httpresponsemessage

I am trying to download a xlsx extension file to be encaspulated as a httpresponsemessage. The file doesn't appear for downloading, however the XHR Requests in chrome seems to contain the data.
public HttpResponseMessage GetExcelFile(string csvdata)
{
var result = new HttpResponseMessage(HttpStatusCode.OK);
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
MemoryStream memStream = new MemoryStream(encoding.GetBytes(csvdata));
result.Content = new ByteArrayContent(encoding.GetBytes(csvdata));
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = "Data.xlsx";
return result;
}
This is the api call that throws the httpresponsemessage into angularjs UI.
Any suggestions to get this to work?.
Hoping that you are using web API get method to return HttpResponseMessage in ValuesController.cs class. ( // GET: api/Values)
assume that ng-click fires at your button click,
add ng-click="TakeIT()" as attribute in button element.
in your angular controller, bind the function to $scope as,
$scope.TakeIT= function () {
window.location = 'api/Values';
};

Using CSVHelper to output stream to browser but unable to save file

I am trying to achieve exactly what the poster in this question is trying to do except the browser (Chrome) doesn't attempt to download the .csv file or present the user with a download box. I am using a HTTP GET request and the code is virtually identical in the question above. I'm using Fiddler to monitor the traffic and I can see the .csv file stream in the response, but the browser seems to be ignore it and I can't work out why...
Here is my current implemenation (base on #MattThrower's question):
I make an AJAX call to the MVC controller:
$("#exportToCsvLink").click(function () {
$.ajax({
type: "GET",
url: window.project.common.routes.urls.ExportChartDataToCsv,
data: { parameterId: parameter.parameterId }
});
});
The MVC controller processes the CSV export and returns a FileStreamResult
public FileStreamResult ExportChartDataToCsv(int parameterId)
{
List<TestViewModel> data = _CommonService.GetData(parameterId);
var result = WriteCsvToMemory(data);
var memoryStream = new MemoryStream(result);
return new FileStreamResult(memoryStream, "text/csv") { FileDownloadName = "export.csv" };
}
public byte[] WriteCsvToMemory(IEnumerable<TestViewModel> data)
{
using (var memoryStream = new MemoryStream())
using (var streamWriter = new StreamWriter(memoryStream))
using (var csvWriter = new CsvWriter(streamWriter))
{
csvWriter.WriteRecords(data);
streamWriter.Flush();
return memoryStream.ToArray();
}
}

Categories