Consuming ASP.NET Web API from classic ASP to download file - c#

I have a legacy Classic ASP application that serves as a repository for a bunch of files available for download. I would prefer to not rewrite the entire application at this time but instead want to pull out the file download logic into an ASP.NET Web API.
I have created the service and when I hit the service via my browser the download starts just fine with the hardcoded filename I have in the app and I am able to save. I am having trouble consuming the service from my asp app however. If I modify the code below to just return a JSON value, I am able to return the value to the asp app. So I at least know there is communication happening. Just not sure how to handle a file download.
HERE IS MY SERVICE LOGIC:
// GET api/values/5
public HttpResponseMessage Get(int id)
{
//return "value";
HttpResponseMessage httpResponseMessage = new HttpResponseMessage();
string filePath = "H:/Temp/Filename.exe";
MemoryStream memoryStream = new MemoryStream();
FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read);
byte[] bytes = new byte[file.Length];
file.Read(bytes, 0, (int)file.Length);
memoryStream.Write(bytes, 0, (int)file.Length);
file.Close();
httpResponseMessage.Content = new ByteArrayContent(memoryStream.ToArray());
httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
httpResponseMessage.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = "Filename.exe" };
httpResponseMessage.StatusCode = HttpStatusCode.OK;
return httpResponseMessage;
}
HERE IS A SUBSET OF MY CLASSIC ASP LOGIC:
Response.Addheader "Content-Disposition", "attachment; filename=Filename.exe"
Response.ContentType = "application/octet-stream" 'EXE
Set HttpReq = Server.CreateObject("MSXML2.ServerXMLHTTP")
HttpReq.open "GET", "http://webservice/api/values/1", False
HttpReq.send
Response.BinaryWrite HttpReq.responsestream

What about something like:
Set HttpReq = Server.CreateObject("ADODB.Stream")
HttpReq.open "GET", "http://webservice/api/values/1", False
Response.BinaryWrite HttpReq.read

Related

How to convert asp web api byte[] to pdf file in Angular 8?

I've been having some problems when I try to convert a byte[] coming from C# into a pdf file using Angular.
When I perform the conversion the file is created but is corrupted and it can't be opened "We can't open this file", the file content is just basic text "Hello world".
Please let me know if you have any answer to this problem, the code I am using is below and I also try using "import { saveAs } from 'file-saver';" but it didn't work.
// THE WEB API CONTROLLER THAT GETS THE PDF BYTE ARRAY
[HttpPost("CreatePDF")]
public async Task<HttpResponseMessage> CreatePDF([FromBody] PDFContent pdfContent)
{
byte[] pdf = await _pdfGenerator.GeneratePDF(pdfContent.HtmlContent);
var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent(pdf);
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
return result;
}
// UI SERVICE LAYER THAT CALLS THE SERVER SIDE
createPdfReport(pdfContent: PDFContent): Observable<any> {
return this.restApi.create("CreatePDF",pdfContent).pipe(
tap(pdf =>
console.log('pdf = ' + pdf)
));
}
// THE COMPONENT THAT CALLS THE SERVICE LAYER AND WAITS FOR THE RESPONSE
this.historyService.createPdfReport(pdfContent).subscribe(data => {
var file = new Blob(data, { type: 'application/octet-stream' })
var fileURL = URL.createObjectURL(data);
const link = document.createElement('a');
link.setAttribute('target', '_blank');
link.setAttribute('href', fileURL);
link.setAttribute('download', `file.pdf`);
document.body.appendChild(link);
link.click();
link.remove();
});
}
This is the response I get in Angular after the controller returns the byte[]:

web api 2 - excel spreadsheet (the file is corrupt and cannot be opened)

I am trying to download a simple xlsx file using web api but the file is always corrupt and I am yet to figure out why.I am using C# ClosedXML.Excel and following a basic example which can be found here:
ClosedXml examples
[HttpGet]
[Route("campaigns/{id}/contact-points/excel")]
[SwaggerResponse(491, "TokenInvalid")]
[SwaggerResponse(HttpStatusCode.NotFound)]
[SwaggerResponse(HttpStatusCode.Forbidden)]
[ResponseType(typeof(HttpResponseMessage))]
public async Task<IHttpActionResult> GetCampaignContactPointsExcel(int id, int frequency, string txtFrequency)
{
var wb = new XLWorkbook();
var ws1 = wb.Worksheets.Add("Sheet1");
ws1.Cell("A1").SetValue(1).AddToNamed("value1");
var ws2 = wb.Worksheets.Add("Sheet2");
ws2.Cell("A1").SetFormulaA1("=value1").AddToNamed("value2");
var responseMessage = new HttpResponseMessage(HttpStatusCode.OK);
using (var memoryStream = new MemoryStream())
{
wb.SaveAs(memoryStream);
responseMessage.Content = new ByteArrayContent(memoryStream.ToArray());
responseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
responseMessage.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "ContactPoints.xlsx"
};
memoryStream.Close();
}
return ResponseMessage(responseMessage);
}
I am also using swagger and when I click on the link it downloads the file and opens it as a xlsx file but it always says it's corrupt.
There is nothing wrong in the backend code. On the frontend side you need to set responseType='blob'
Seems like this is an issue related to swagger ui 2. Please refer to [https://github.com/swagger-api/swagger-ui/issues/1605][1].
You can try curl or Postman to see if it downloads the file correctly.
While calling the service set Response type as 'blob'
return this.http.get(this.url +'PA/Downloadexcel/'+revisionId,{ responseType :'blob'});

How to Post a web request and receive a file from web API response?

I have an Infopath Form Template on Sharepoint, I want to add a button there so when the user clicks on it, it will POST an string to the following Web API. The following web API is tested and returns an excel file as shown:
I want to Post the FileName of the excel file using post request and it is important for me the request method to be POST type. and then the user will download a file with the specified 'FileName'.
Actually i want to use post method because at the next stage i will send the content of the excel file too.
Important Note: I only can use .Net FrameWork 3.5 because this is the only framework supported in InfoPath Form Templates.
[HttpPost]
public HttpResponseMessage Post([FromBody]string FileName)
{
string reqBook = "c:\somefile.xlsx";
//converting Excel(xlsx) file into bytes array
var dataBytes = File.ReadAllBytes(reqBook);
//adding bytes to memory stream
var dataStream = new MemoryStream(dataBytes);
HttpResponseMessage httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK);
httpResponseMessage.Content = new StreamContent(dataStream);
httpResponseMessage.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
httpResponseMessage.Content.Headers.ContentDisposition.FileName = FileName;
httpResponseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
return httpResponseMessage;
}
When you perform the HttpPost on the client side, you will want to read the HttpResponseStream to get the byte data of the response stream.
Once you have the response stream data, you can then deserialize it to the type of object in C# you want, or you could alternatively just write it to the disk as
File.WriteAllBytes("someexcel.xlsx",data);
An easy way to do it would be with the HttpClient class.
HttpClient client = new HttpClient();
var response = client.PostAsync("", null).Result;
var content = response.Content.ReadAsByteArrayAsync().Result;
File.WriteAllBytes("excel.xlsx", content);
Just fill in the PostAsync bit with the Url and the content you wish to post.
I am using .Result to keep everything synchronous - but you can use 'await' if you prefer.
If you are working with HttpWebRequests - then the process becomes more complicated, as you need to manage the streams yourself.
The HttpClient will manage and handle it all for you - so I recommend it, unless there is something special it needs to do that it currently does not.
Due to your .Net 3.5 requirement:
private static HttpWebResponse MakeRequest(string url, string postArgument)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "multipart/form-data;";
Stream stream = request.GetRequestStream();
string result = string.Format("arg1={0}", postArgument);
byte[] value = Encoding.UTF8.GetBytes(result);
stream.Write(value, 0, value.Length);
stream.Close();
return (HttpWebResponse)request.GetResponse();
}
You can then do:
var response = MakeRequest("http://mywebsite.com/ProcessExcel", "accounts.xlsx");
And then do
Stream objStream = response .GetResponseStream();
BinaryReader breader = new BinaryReader(objStream);
byte[] data= breader.ReadBytes((int)webresponse.ContentLength);
File.WriteAllBytes("excel.xlsx",data);

Encoding issue with file on AWS Lambda/API Gateway

I'm producing a REST API that does some file conversion / processing.
My Visual Studio 2015 and building on an AWS Serverless Core - ASP.Net Core Web API template.
I'm running some initial test methods and have encountered what appears to be an encoding issue.
My controller has the following. It simply pulls the posted file into a byte array via a memory stream and then passes it back. (The final application will process the byte array)
[HttpPost]
public IActionResult Post(IFormFile file)
{
var inputStream = new MemoryStream();
file.CopyTo(inputStream);
var fileBytes = inputStream.ToArray();
var outputStream = new MemoryStream(fileBytes);
return File(outputStream, "application/octet-stream");
}
I then have a test application I'm using to pass a file to this controller and save the return.
using (var client = new HttpClient())
{
using (var content = new MultipartFormDataContent())
{
var inputFileStream = new FileStream(Server.MapPath("~/App_Data/InputFile.pdf"), FileMode.Open, FileAccess.Read);
var inputFileBytes = new Byte[inputFileStream.Length];
inputFileStream.Read(inputFileBytes, 0, inputFileBytes.Length);
inputFileStream.Close();
content.Add(new ByteArrayContent(inputFileBytes), "file", "InputFile.pdf");
var requestUri = "http://localhost:5000/api/controller";
//var requestUri = "https://xxxxxxxxxx.execute-api.eu-west-1.amazonaws.com/Prod/api/controller";
var result = client.PostAsync(requestUri, content).Result;
var resultStream = result.Content.ReadAsStreamAsync().Result;
var memoryStream = new MemoryStream();
resultStream.CopyTo(memoryStream);
var outputFileBytes = memoryStream.ToArray();
FileStream outputFileStream = new FileStream(Server.MapPath("~/App_Data/OutputFile.pdf"), FileMode.Create, FileAccess.ReadWrite);
outputFileStream.Write(outputFileBytes, 0, outputFileBytes.Length);
outputFileStream.Close();
}
}
When I run using the localhost application, the duplicate file is saved back. However, when I publish the API to AWS, the file returned is exactly double in size to the original, certainly indicated an encoding issue.
If I pass an ANSI text file with the contents TEST then the saved file contains VEVTVA==
Can someone point me at where I should be setting any encoding settings and any suggested settings to ensure that the output stream from my HttpClient is the same as my input?
So I noticed this as well with a AWS ASP.Net Core Web API. I changed the MIME type from application/octet-stream to application/text and that seemed to fix it on AWS.
[HttpPost]
public IActionResult Post(IFormFile file)
{
var inputStream = new MemoryStream();
file.CopyTo(inputStream);
var fileBytes = inputStream.ToArray();
var outputStream = new MemoryStream(fileBytes);
return File(outputStream, "application/text");
}

get the file url from c# controller via jquery

I have a c# controller that returns a status file for the system. It prompts the user to open or download the file. The return type for the controller is actually System.Net.Http.HttpResponseMessage.
I set up the route like this: /api/logging/status/{reqID}
If I goto the route directly in my web browser, http://mysite//api/logging/status/12345678, it works fine.
How can I get the URL to the file via jquery so that I can put that url in an achor tag like:
Download Status
Here is the controller:
[Route("/api/logging/status/{reqID}")]
public IHttpActionResult GetStatus(Int32 reqID)
{
Stream stream;
stream = new MemoryStream();
var reqStatus = serializer.SerializeToString(req);
var bytes = System.Text.Encoding.UTF8.GetBytes(reqStatus);
stream.Write(bytes, 0, bytes.Length);
stream.Seek(0, SeekOrigin.Begin);
}
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(stream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.Add("Content-Disposition", String.Format("attachment; filename=\"{0}\"", "status.txt"));
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
return ResponseMessage(response);
}
Is there something I'm missing?
Thanks!
Have you already tried the following?
$.get('/api/logging/status/12345678', function (data) {
console.log(data);
});
#999cm999,
It seems to me that you need another service method to serve the path to the txt file. You only have a method that serves the file itself as a download. That's how the browser example works.
However, if you want to insert the path to the txt file (http://path.to.my.status.file/status.txt) in an anchor tag of your HTML page, the method that you have does not fit. Create another method that returns the path to the file as a string. Then you can grab that and put it in the HREF attribute of your hyperlink element using jQuery or your favorite JS approach.
Let me know of your findings.

Categories

Resources