download a file from asp.net api in xamarin form? [duplicate] - asp.net

I am trying to save a file to the client's machine. I want to require the client to pick the location of the download.
I have endpoint of the REST service which returns the file to be downloaded. I am trying to set up the code to download the file thats returned from the service with save as dialog.
var Url = "https://randomaddresss/v5/invoices/{" + InvoicesId + "}/getpdfbyid";
HttpResponse response = HttpContext.Current.Response;
response.ClearContent();
response.Clear();
response.ContentType = "application/pdf";
response.AddHeader("Content-Disposition", "attachment; filename=" + InvoicesId + ".pdf;");
response.TransmitFile(Url);
response.Flush();
response.End();
The error thats returned is on the line response.TransmitFile(Url); :
'https:/randomaddresss/v5/invoices/2131231231231312/getpdfbyid'
is not a valid virtual path.

HttpResponse.TransmitFile expects a file path, not a URL.
You will need to download the file first, then write to the response stream.
Here's an example using HttpClient:
using var invoiceResponse = await httpClient.GetAsync(Url);
using var invoiceStream = await invoiceResponse.Content.ReadAsStreamAsync();
invoiceStream.CopyTo(response.OutputStream);
response.ContentType = "application/pdf";
response.AddHeader("Content-Disposition", "attachment; filename=" + InvoicesId + ".pdf;");

JS:
function downloadPdfInvoice(iId) {
$.ajax({
url: '/api/DownloadInvoice?Invoice=' + iId,
type: 'get',
success: function (response, status) {
if (response) {
var link = document.createElement('a');
link.href = "data:application/octet-stream;base64," + response.Data;
link.target = '_blank';
link.download = iId + '.pdf';
link.click();
}
},
});
}
CS:
[HttpGet]
public ApiResponse DownloadInvoiceAsync(string InvoicesId)
{
try
{
String Url = "https://test/{" + InvoicesId + "}/getpdfinvoice";
HttpWebRequest fileReq = (HttpWebRequest)HttpWebRequest.Create(Url);
var resp = fileReq.GetResponse();
Stream input = resp.GetResponseStream();
byte[] data = input.ReadAsBytes();
return new ApiResponse(true, "Downloadet til skrivebordet.", data);
}
catch (Exception ex)
{
Logger.Warn(MethodBase.GetCurrentMethod().DeclaringType,
string.Format("DownloadInvoice Exception {0}", ex.Message));
throw ex;
}
}

Related

Problems with downloading pdf file from web api service

I'm trying to set up a web api service that searches for a .pdf file in a directory and returns the file if it's found.
The controller
public class ProductsController : ApiController
{
[HttpPost]
public HttpResponseMessage Post([FromBody]string certificateId)
{
string fileName = certificateId + ".pdf";
var path = #"C:\Certificates\20487A" + fileName;
//check the directory for pdf matching the certid
if (File.Exists(path))
{
//if there is a match then return the file
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(path, FileMode.Open);
stream.Position = 0;
result.Content = new StreamContent(stream);
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment") { FileName = fileName };
result.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
result.Content.Headers.ContentDisposition.FileName = fileName;
return result;
}
else
{
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.Gone);
return result;
}
}
}
I'm calling the service with the following code
private void GetCertQueryResponse(string url, string serial)
{
string encodedParameters = "certificateId=" + serial.Replace(" ", "");
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.Method = "POST";
httpRequest.ContentType = "application/x-www-form-urlencoded";
httpRequest.AllowAutoRedirect = false;
byte[] bytedata = Encoding.UTF8.GetBytes(encodedParameters);
httpRequest.ContentLength = bytedata.Length;
Stream requestStream = httpRequest.GetRequestStream();
requestStream.Write(bytedata, 0, bytedata.Length);
requestStream.Close();
HttpWebResponse response = (HttpWebResponse)httpRequest.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
byte[] bytes = null;
using (Stream stream = response.GetResponseStream())
using (MemoryStream ms = new MemoryStream())
{
int count = 0;
do
{
byte[] buf = new byte[1024];
count = stream.Read(buf, 0, 1024);
ms.Write(buf, 0, count);
} while (stream.CanRead && count > 0);
ms.Position = 0;
bytes = ms.ToArray();
}
var filename = serial + ".pdf";
Response.ContentType = "application/pdf";
Response.Headers.Add("Content-Disposition", "attachment; filename=\"" + filename + "\"");
Response.BinaryWrite(bytes);
}
}
This appears to be working in the sense that the download file dialogue is shown with the correct file name and size etc, but the download takes only a couple of seconds (when the file sizes are >30mb) and the files are corrupt when I try to open them.
Any ideas what I'm doing wrong?
Your code looks similar to what Ive used in the past, but below is what I typically use:
Response.AddHeader("content-length", myfile.Length.ToString())
Response.AddHeader("content-disposition", "inline; filename=MyFilename")
Response.AddHeader("Expires", "0")
Response.AddHeader("Pragma", "Cache")
Response.AddHeader("Cache-Control", "private")
Response.ContentType = "application/pdf"
Response.BinaryWrite(finalForm)
I post this for 2 reasons. One, add the content-length header, you may have to indicate how large the file is so the application waits for the whole response.
If that doesn't fix it. Set a breakpoint, does the byte array content the appropriate length (aka, 30 million bytes for a 30 MB file)? Have you used fiddler to see how much content is coming back over the HTTP call?

Google Drive api uploads file name as "Untitled"

I can upload file to google drive from my website, but my problem is it will show the file as Untitled after uploading.
How can I add or post title to the uploading file.
Thanks,
My Code:
public string UploadFile(string accessToken, byte[] file_data, string mime_type)
{
try
{
string result = "";
byte[] buffer = file_data;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/upload/drive/v2/files?uploadType=media");
request.Method = "POST";
request.ContentType = mime_type;
request.ContentLength = buffer.Length;
request.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + accessToken);
var stream = request.GetRequestStream();
stream.Write(file_data, 0, file_data.Length);
stream.Close();
HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse();//Get error here
if(webResponse.StatusCode == HttpStatusCode.OK)
{
Stream responseStream = webResponse.GetResponseStream();
StreamReader responseStreamReader = new StreamReader(responseStream);
result = responseStreamReader.ReadToEnd();//parse token from result
var jLinq = JObject.Parse(result);
JObject jObject = JObject.Parse(jLinq.ToString());
webResponse.Close();
return jObject["alternateLink"].ToString();
}
return string.Empty;
}
catch
{
return string.Empty;
}
}
I used RestSharp for uploading a file to google drive.
public static void UploadFile(string accessToken, string parentId)
{
var client = new RestClient { BaseUrl = new Uri("https://www.googleapis.com/") };
var request = new RestRequest(string.Format("/upload/drive/v2/files?uploadType=multipart&access_token={0}", accessToken), Method.POST);
var bytes = File.ReadAllBytes(#"D:\mypdf.pdf");
var content = new { title = "mypdf.pdf", description = "mypdf.pdf", parents = new[] { new { id = parentId } }, mimeType = "application/pdf" };
var data = JsonConvert.SerializeObject(content);
request.AddFile("content", Encoding.UTF8.GetBytes(data), "content", "application/json; charset=utf-8");
request.AddFile("mypdf.pdf", bytes, "mypdf.pdf", "application/pdf");
var response = client.Execute(request);
if (response.StatusCode != HttpStatusCode.OK) throw new Exception("Unable to upload file to google drive");
}
Doing it with out using the google.apis dlls isnt that easy. You need to send the meta data before you send the rest of the file. For that you need to use uploadType=multipart
https://developers.google.com/drive/manage-uploads#multipart
This should get you started sorry its a wall of code. I havent had time to create a tutorial for this yet.
FileInfo info = new FileInfo(pFilename);
//Createing the MetaData to send
List<string> _postData = new List<string>();
_postData.Add("{");
_postData.Add("\"title\": \"" + info.Name + "\",");
_postData.Add("\"description\": \"Uploaded with SendToGoogleDrive\",");
_postData.Add("\"parents\": [{\"id\":\"" + pFolder + "\"}],");
_postData.Add("\"mimeType\": \"" + GetMimeType(pFilename).ToString() + "\"");
_postData.Add("}");
string postData = string.Join(" ", _postData.ToArray());
byte[] MetaDataByteArray = Encoding.UTF8.GetBytes(postData);
// creating the Data For the file
byte[] FileByteArray = System.IO.File.ReadAllBytes(pFilename);
string boundry = "foo_bar_baz";
string url = "https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart" + "&access_token=" + myAutentication.accessToken;
WebRequest request = WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "multipart/related; boundary=\"" + boundry + "\"";
// Wrighting Meta Data
string headerJson = string.Format("--{0}\r\nContent-Type: {1}\r\n\r\n",
boundry,
"application/json; charset=UTF-8");
string headerFile = string.Format("\r\n--{0}\r\nContent-Type: {1}\r\n\r\n",
boundry,
GetMimeType(pFilename).ToString());
string footer = "\r\n--" + boundry + "--\r\n";
int headerLenght = headerJson.Length + headerFile.Length + footer.Length;
request.ContentLength = MetaDataByteArray.Length + FileByteArray.Length + headerLenght;
Stream dataStream = request.GetRequestStream();
dataStream.Write(Encoding.UTF8.GetBytes(headerJson), 0, Encoding.UTF8.GetByteCount(headerJson)); // write the MetaData ContentType
dataStream.Write(MetaDataByteArray, 0, MetaDataByteArray.Length); // write the MetaData
dataStream.Write(Encoding.UTF8.GetBytes(headerFile), 0, Encoding.UTF8.GetByteCount(headerFile)); // write the File ContentType
dataStream.Write(FileByteArray, 0, FileByteArray.Length); // write the file
// Add the end of the request. Start with a newline
dataStream.Write(Encoding.UTF8.GetBytes(footer), 0, Encoding.UTF8.GetByteCount(footer));
dataStream.Close();
try
{
WebResponse response = request.GetResponse();
// Get the stream containing content returned by the server.
dataStream = response.GetResponseStream();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Display the content.
//Console.WriteLine(responseFromServer);
// Clean up the streams.
reader.Close();
dataStream.Close();
response.Close();
}
catch (Exception ex)
{
return "Exception uploading file: uploading file." + ex.Message;
}
If you need any explinations beyond the comments let me know. I strugled to get this working for a month. Its almost as bad as resumable upload.
I was searching for the solution of the given problem and previously I was putting uploadType=resumable that causes the given issue and when I used uploadType=multipart problem is resolved...

Downloading file on client side using absolute path .NET

string FilePath = HttpUtility.UrlDecode(Request.QueryString.ToString());
string[] s = FilePath.Split(new char[] { ',' });
string path = s[0];
string FileName = s[1];
String str = HttpContext.Current.Request.Url.AbsolutePath;
System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
response.ClearContent();
response.Clear();
// response.ContentType = "text/plain";
response.AddHeader("Content-Disposition", "attachment; filename=" + FileName+ ";");
response.TransmitFile(path+FileName);
response.Flush();
response.End();
Above is the code in which i get location of audio file from another page . the audio file is located on a remote machine which is accesible using url e.g. http:\servername\audiofiles\filename.wav . response.Transmit and .WriteFile requires virtual path whereas response.Write() does not download file . How can i give the absolute url instead of virtual path to download file
Found the answer my self from another place :
string FilePath = HttpUtility.UrlDecode(Request.QueryString.ToString());
string[] s = FilePath.Split(new char[] { ',' });
string path = s[0];
string FileName = s[1];
int bytesToRead = 10000;
byte[] buffer = new Byte[bytesToRead];
try
{
HttpWebRequest fileReq = (HttpWebRequest)HttpWebRequest.Create(path+FileName);
HttpWebResponse fileResp = (HttpWebResponse)fileReq.GetResponse();
if (fileReq.ContentLength > 0)
fileResp.ContentLength = fileReq.ContentLength;
stream = fileResp.GetResponseStream();
var resp = HttpContext.Current.Response;
resp.ContentType = "application/octet-stream";
resp.AddHeader("Content-Disposition", "attachment; filename=\"" + FileName + "\"");
resp.AddHeader("Content-Length", fileResp.ContentLength.ToString());
int length;
do
{
if (resp.IsClientConnected)
{
// Read data into the buffer.
length = stream.Read(buffer, 0, bytesToRead);
// and write it out to the response's output stream
resp.OutputStream.Write(buffer, 0, length);
resp.Flush();
//Clear the buffer
buffer = new Byte[bytesToRead];
}
else
{
// cancel the download if client has disconnected
length = -1;
}
} while (length > 0); //Repeat until no data is read
}
finally
{
if (stream != null)
{
//Close the input stream
stream.Close();
}
}
}

Path issue with wkhtmltopdf.exe to convert HTML file to PDF

I am using wkhtmltopdf to convert HTML file into PDF document on a link Button
http://code.google.com/p/wkhtmltopdf/
When User Click on a link Button it runs the following code as shown below code in pass file path as an argument ProcessStartInfo. THis code works fine in Following Scenarios only
Taking Into consideration that website is hosted on Domain http://www.xyz.net/
When i mention path as http://demo.XYZ.net/ It works fine
When i mention path as http://www.XYZ.net/ It doesn't work
In-case of local-host it works fine if path is http://localhost:51005/XYZ/or http://web:8080/
For this to work properly we need to give the website full trust level & i am not sure why code doesn't run i give it the same domain path if i create put PrintArticle.aspx if i create a sub domain then it will work fine. I am nost sure if this is a security problem or what
Code Below
protected void lnkbtnDownload_Click(object sender, EventArgs e)
{
//ConvertURLToPDF();
try
{
string url = "PrintArticle.aspx?articleID=" + Request["articleID"] + "&download=yes&Language=" + Request["Language"];
//string args = string.Format("\"{0}\" - ", "http://demo.XYZ.net/" + url); //Works
//string args = string.Format("\"{0}\" - ", "http://www.xyz.net/" + url); Doesnt work
//string args = string.Format("\"{0}\" - ", url);
string args = string.Format("\"{0}\" - ", "http://localhost:51005/XYZ/" + url); //Works
var startInfo = new ProcessStartInfo(Server.MapPath("bin\\wkhtmltopdf.exe"), args)
{
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true
};
var proc = new Process { StartInfo = startInfo };
proc.Start();
string output = proc.StandardOutput.ReadToEnd();
byte[] buffer = proc.StandardOutput.CurrentEncoding.GetBytes(output);
proc.WaitForExit();
proc.Close();
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", "attachment;filename=download.pdf");
Response.BinaryWrite(buffer);
Response.End();
}
catch (Exception ex)
{
throw ex;
}
}
Error Message in case file is on same domain
Server Error in '/' Application. The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its
dependencies) could have been removed, had its name changed, or is
temporarily unavailable. Please review the following URL and make sure
that it is spelled correctly.
Requested URL: /PrintArticle.aspx
Version Information: Microsoft .NET Framework Version:4.0.30319;
ASP.NET Version:4.0.30319.272
I resolved this issue by using the following statement
var url = Request.Url.GetLeftPart(UriPartial.Authority) + "/PrintArticle.aspx?articleID=" + Request["articleID"] + "&download=yes&Language=" + Request["Language"];
Now it is working fine i am not sure what it doesn't work when i specify the file path.
output variable contains empty string
my code as follows:
try
{
string url=Request.Url.GetLeftPart(UriPartial.Authority) +"/PrintQuickPrescription.aspx?DoctorId=" + DoctorID + "&DispnID=" + DispnID + "&ApptID=" + ApptID + "&PatientID=" + PatientID;
System.Diagnostics.Process process = new System.Diagnostics.Process();
string args = string.Format("\"{0}\" - ", "http://localhost:50013/DPMNewWeb/"+url);
//string args="http://localhost:50013/DPMNewWeb/PrintQuickPrescription.aspx";
var startInfo = new ProcessStartInfo(Server.MapPath("~\\Bin\\wkhtmltopdf.exe"), args)
{
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true
};
var proc = new Process { StartInfo = startInfo };
proc.Start();
string output = proc.StandardOutput.ReadToEnd();
byte[] buffer = proc.StandardOutput.CurrentEncoding.GetBytes(output);
proc.WaitForExit();
proc.Close();
Response.ContentType = "application/pdf";
Response.BinaryWrite(buffer);
Response.End();
//byte[] fileContent = GeneratePDFFile();
//GeneratePDFFile();
//if (fileContent != null)
//{
// Response.Clear();
// Response.ContentType = "application/pdf";
// Response.AddHeader("content-length", fileContent.Length.ToString());
// Response.BinaryWrite(fileContent);
// Response.End();
//}
}
catch
{
}

How can I output to a webform before I clear a response?

I have a Webform where a user clicks a button and an Excel file is generated.
This is achieved by this code:
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=export.txt");
Response.ContentType = "text/csv";
Response.WriteFile(FILENAME);
Response.End();
I would like to add to the Response so when the user closes Excel, they can see a message on the Webform.But you can't do this in the code above.
Response.Write("Excel generated!"); ************ does not work as response will be cleared!
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=donman_export.txt");
Response.ContentType = "text/csv";
Response.WriteFile(FILENAME);
Response.End();
How can I do this?
Response.Write("Excel generated!"); ************ does not work
Response.Flush();
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=donman_export.txt");
Response.ContentType = "text/csv";
Response.WriteFile(FILENAME);
Response.End();
Code below is doing exactly what have you asked.
It renders additional HTML tags, so download starts after message was shown to user:
protected void Page_Load(object sender, EventArgs e)
{
var currentUrl = Request.Url.OriginalString;
var currentQuery = Request.Url.Query;
var download = new
{
FilePath = "~/test.csv",
FileName = "test.csv",
FileMime = "text/csv",
Message = "Excel generated!",
QueryParam = "direct-download",
Delay = 2 // seconds
};
var hasQueryParams = currentQuery.Length > 0;
var isDownloadUrl = hasQueryParams && currentQuery.IndexOf( download.QueryParam ) >= 0;
if( isDownloadUrl )
{
// Prepare..
Response.ContentType = download.FileMime;
Response.Clear();
Response.BufferOutput = true;
// Transfer..
Response.AddHeader("content-disposition", "attachment; filename=" + download.FileName);
Response.WriteFile(download.FilePath);
// Done..
// Instead of Response.Close()
// http://stackoverflow.com/q/4583201/2361743
Response.Flush();
Context.ApplicationInstance.CompleteRequest();
return;
}
// Meta-Refresh Tag has to be in <HEAD> section, but not all browsers follow this restriction.
// IFRAME has to work fine. It is wrapped into <DIV> to be not visible in old browsers.
const string tagToStartManual = "<A href='{0}'>{1}</A>";
const string tagToStartAfterDelay = "<META HTTP-EQUIV='REFRESH' CONTENT='{1};URL={0}'>";
const string tagToStartImmediately = "<DIV STYLE='{1}'><IFRAME SRC='{0}'></IFRAME></DIV>";
const string cssToHideFrame = "width:1px;height:1px;opacity:0.1;overflow:hidden";
// Show your message..
// And add HTML Tags which would start download:
Response.Write(download.Message);
var downloadUrl = currentUrl + (hasQueryParams ? "&" : "?") + download.QueryParam;
// You don't have to use all 3 methods...
Response.Write( String.Format( tagToStartManual, downloadUrl, download.FileName));
Response.Write( String.Format( tagToStartAfterDelay, downloadUrl, download.Delay) );
Response.Write( String.Format( tagToStartImmediately, downloadUrl, cssToHideFrame) );
// Done.
// Waiting for actual download request...
}

Resources