I am trying to download a file over a RESTful Webservice and then save the file on the computer.
I am using an PDF-File to test the code. I found out the data is UTF-8 encoded so i tried encoding it back to default, because i found out by reading the pdf file locally and writing it back again that it works that way.
Here is my code:
IConsumerRequest getDocumentRequest = class.consumerSession
.Request()
.ForMethod("GET")
.ForUri(new Uri(class.apiEndpoint + "/1/documents/" + id))
.SignWithToken(class.accessToken);
string test = System.IO.File.ReadAllText("C:\\test.pdf", Encoding.Default);
byte[] bytes = Encoding.UTF8.GetBytes(getDocumentRequest.ToString());
string data = Encoding.Default.GetString(bytes);
MessageBox.Show(test.Substring(0, 120) + "\n\n" + data.Substring(0, 120));
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.FileName = dataGridView1.Rows[e.RowIndex].Cells[2].Value.ToString();
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
System.IO.File.WriteAllBytes(saveFileDialog.FileName, bytes);
}
Comparing the string shows the following (second line):
Local String vs String from Webservice
I already tried several ways to convert the string without any difference.
You can use the Encoding.Convert method.
byte[] converted = Encoding.Convert(Encoding.UTF8, Encoding.Default, bytes);
Got it to work with HttpWebResponse:
HttpWebResponse webResponse = getDocumentRequest.ToWebResponse();
Stream stream = webResponse.GetResponseStream();
Encoding enc = System.Text.Encoding.GetEncoding(UTF8);
StreamReader loResponseStream = new StreamReader(webResponse.GetResponseStream(), enc);
string serverResponse = loResponseStream.ReadToEnd();
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.FileName = dataGridView1.Rows[e.RowIndex].Cells[2].Value.ToString();
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
System.IO.File.WriteAllText(saveFileDialog.FileName, serverResponse, Encoding.Default);
}
Related
This question already has an answer here:
FromBase64String/UTF Encoding
(1 answer)
Closed 2 years ago.
I am trying to download a PDF file and encode it in UTF-8 format and then transform it back into a Base64 to attach it to a MailMessage, however I get an exception when passing the string to Base64.
exception
The input is not a valid Base-64 string as it contains a non-base 64 character...
my code...
try
{
if (attachment.Uri.Contains("http") || attachment.Uri.Contains("https"))
{
byte[] contentByte = null;
using (var webClient = new WebClient())
{
webClient.UseDefaultCredentials = true;
Uri uri = new Uri(attachment.Uri);
contentByte = webClient.DownloadData(uri);
}
MemoryStream memStream = new MemoryStream(contentByte);
String fullString = Encoding.UTF8.GetString(memStream.ToArray());
String stringData = fullString.Split(',')[1];
byte[] byteData = System.Convert.FromBase64String(stringData);
MemoryStream streamData = new MemoryStream(byteData);
Attachment attachmentDoc = new Attachment(streamData, fileName);
mail.Attachments.Add(attachmentDoc);
}
}
catch (Exception ex)
{
notificationLog.Error.Write(String.Format("Sendmail error. Attachment not found: " + attachment.FileName));
}
You are going about this the wrong way.
You are trying to decode the PDF as UTF-8 (which it is not) to UTF-16, and then decode that UTF-16 as Base64 (which it is not) to a byte array, then attach those bytes to the email. That is the complete opposite of what you need.
Base64 operates on bytes, not strings/characters. There is no need to encode a PDF (a binary file) to UTF-8 before encoding it in Base64. Just encode the PDF bytes as-is straight to Base64, eg:
try
{
if (attachment.Uri.StartsWith("http:") || attachment.Uri.StartsWith("https:"))
{
byte[] contentByte = null;
using (var webClient = new WebClient())
{
webClient.UseDefaultCredentials = true;
Uri uri = new Uri(attachment.Uri);
contentByte = webClient.DownloadData(uri);
}
String stringData = System.Convert.ToBase64String(contentByte);
MemoryStream memStream = new MemoryStream(Encoding.ASCII.GetBytes(stringData));
Attachment attachmentDoc = new Attachment(memStream, fileName);
mail.Attachments.Add(attachmentDoc);
}
}
catch (Exception ex)
{
notificationLog.Error.Write(String.Format("Sendmail error. Attachment not found: " + attachment.FileName));
}
However, using this approach, the receiver won't be able to decode the PDF correctly, because it won't know the PDF bytes were encoded in Base64.
Fortunately, the Attachment class can handle the Base64 for you, and notify the receiver of the encoding. Just give the Attachment the raw PDF bytes as-is, and set its TransferEncoding property to Base64, eg:
try
{
if (attachment.Uri.StartsWith("http:") || attachment.Uri.StartsWith("https:"))
{
byte[] contentByte = null;
using (var webClient = new WebClient())
{
webClient.UseDefaultCredentials = true;
Uri uri = new Uri(attachment.Uri);
contentByte = webClient.DownloadData(uri);
}
MemoryStream memStream = new MemoryStream(contentByte);
Attachment attachmentDoc = new Attachment(memStream, fileName);
attachmentDoc.TransferEncoding = TransferEncoding.Base64;
mail.Attachments.Add(attachmentDoc);
}
}
catch (Exception ex)
{
notificationLog.Error.Write(String.Format("Sendmail error. Attachment not found: " + attachment.FileName));
}
I have Base64 string that represents a PDF file which needs to be converted to a PDF file, and open with the default PDF reader or browser in C#.
I have written only the part of Base64 string because it's too long string to paste here.
public void DownloadPDF()
{
string pdflocation = "E:\\";
string fileName = "softcore.pdf";
// This is only part of Base64 string
var base64String = "JVBERi0xLjQKJdP0zOEKMSAwIue704O58dOXPgst+hmQ+laj/";
int mod4 = base64String.Length % 4;
if (mod4 > 0)
{
base64String += new string('=', 4 - mod4);
}
byte[] data = Convert.FromBase64String(base64String);
if (Directory.Exists(pdflocation))
{
pdflocation = pdflocation + fileName;
using (MemoryStream Writer = new System.IO.MemoryStream())
{
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment; filename=" + fileName);
Response.AddHeader("content-length", data.Length.ToString());
Writer.WriteTo(Response.OutputStream);
Response.Flush();
Response.End();
//Writer.Write(data, 0, data.Length);
}
}
}
The problem I'm facing is that it shows as pdf generating but at the end, it says Network error.
The decoded string from the input encoded Base64 string:
This code works fine if a PDF is converted base 64 from some online platform like freeformatter.com/base64-encoder.html and use that base 64 string in the code below:
string pdflocation = "D:\\";
string fileName = "softcore.pdf";
// put your base64 string converted from online platform here instead of V
var base64String = V;
int mod4 = base64String.Length % 4;
// as of my research this mod4 will be greater than 0 if the base 64 string is corrupted
if (mod4 > 0)
{
base64String += new string('=', 4 - mod4);
}
pdflocation = pdflocation + fileName;
byte[] data = Convert.FromBase64String(base64String);
using (FileStream stream = System.IO.File.Create(pdflocation))
{
stream.Write(data, 0, data.Length);
}
This should save the PDF file in D:\\ , again the problem is in your base 64 encoded string
Hope this helps.
I am trying to make a program which is able to download files with URI(URL) using httpwebrequest and cookies(for credential information to keep login status).
I can download files with following code but files get corrupted after being downloaded.
when I download xlsx file(on the web page) into text file at local drive, I see some part of numbers and words from an original file in a corrupted file, therefore I assume I have reached to the right file.
however, when I download xlsx file(on the web page) in xlsx file at local drive, it seems like it fails to open saying
excel cannot open the file 'filename.xlsx' because the file format or
file extension is not valid. Verify that the file has not been
corrupted and that the file extension matches the format of the file.
Is there any way I can keep fully original file content after I download?
I attach a part of result content as well.
private void btsDownload_Click(object sender, EventArgs e)
{
try
{
string filepath1 = #"PathAndNameofFile.txt";
string sTmpCookieString = GetGlobalCookies(webBrowser1.Url.AbsoluteUri);
HttpWebRequest fstRequest = (HttpWebRequest)WebRequest.Create(sLinkDwPage);
fstRequest.Method = "GET";
fstRequest.CookieContainer = new System.Net.CookieContainer();
fstRequest.CookieContainer.SetCookies(webBrowser1.Document.Url, sTmpCookieString);
HttpWebResponse fstResponse = (HttpWebResponse)fstRequest.GetResponse();
StreamReader sr = new StreamReader(fstResponse.GetResponseStream());
string sPageData = sr.ReadToEnd();
sr.Close();
string sViewState = ExtractInputHidden(sPageData, "__VIEWSTATE");
string sEventValidation = this.ExtractInputHidden(sPageData, "__EVENTVALIDATION");
string sUrl = ssItemLinkDwPage;
HttpWebRequest hwrRequest = (HttpWebRequest)WebRequest.Create(sUrl);
hwrRequest.Method = "POST";
string sPostData = "__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=" + sViewState + "&__EVENTVALIDATION=" + sEventValidation + "&Name=test" + "&Button1=Button";
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] bByteArray = encoding.GetBytes(sPostData);
hwrRequest.ContentType = "application/x-www-form-urlencoded";
Uri convertedURI = new Uri(ssDwPage);
hwrRequest.CookieContainer = new System.Net.CookieContainer();
hwrRequest.CookieContainer.SetCookies(convertedURI, sTmpCookieString);
hwrRequest.ContentLength = bByteArray.Length;
Stream sDataStream = hwrRequest.GetRequestStream();
sDataStream.Write(bByteArray, 0, bByteArray.Length);
sDataStream.Close();
using (WebResponse response = hwrRequest.GetResponse())
{
using (sDataStream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(sDataStream);
{
string sResponseFromServer = reader.ReadToEnd();
FileStream fs = File.Open(filepath1, FileMode.OpenOrCreate, FileAccess.Write);
Byte[] info = encoding.GetBytes(sResponseFromServer);
fs.Write(info, 0, info.Length);
fs.Close();
reader.Close();
sDataStream.Close();
response.Close();
}
}
}
}
catch
{
MessageBox.Show("Error");
}
}
StreamReader is for dealing with text data. Using it corrupts your binary data(excel file).
Write sDataStream directly to file. For ex.
sDataStream.CopyTo(fs)
PS: I prepared a test case (using similar logic) to show how your code doesn't work
var binaryData = new byte[] { 128,255 };
var sr = new StreamReader(new MemoryStream(binaryData));
var str3 = sr.ReadToEnd();
var newData = new ASCIIEncoding().GetBytes(str3); //<-- 63,63
Just compare binaryData with newData
I have been able to download a zipfile before but then the compression happend on the ASP server. Now we have changed this action to another server (Progress).
At this moment I'm receiving a base64 encoded string which represents a zip file. But how can I convert this string to a zipfile. The code I used before you can find beneath, can I reuse code?
MemoryStream outputStream = new MemoryStream();
outputStream.Seek(0, SeekOrigin.Begin);
using (ZipFile zip = new ZipFile())
{
foreach (string id in idArray)
{
string json = rest.getDocumentInvoice(Convert.ToInt32(id));
byte[] file = json.convertJsonToFile();
zip.AddEntry("invoice" + id + ".pdf", file);
}
zip.Save(outputStream);
}
outputStream.WriteTo(Response.OutputStream);
Response.AppendHeader("content-disposition", "attachment; filename=invoices.zip");
Response.ContentType = "application/zip";
return new FileStreamResult(outputStream, "application/zip");
I have no idea how to convert a string to a zip file. Thanks in advance for your help
Convert the base64 to a byte array by doing:
Convert.fromBase64String(strBase64);
Then I found an article to easily download the zipfile
Download file of any type in Asp.Net MVC using FileResult?
This article suggests:
public FileResult Download()
{
string base64 = getBase64ZIP();
byte[] byteArray = Convert.fromBase64String(base64);
return File(byteArray, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}
Use Convert.FromBase64String to get the bytes of the zip file.
string base64String = rest.getDocumentInvoice(Convert.ToInt32(id));
byte[] file = Convert.FromBase64String(base64String);
using(var stream = new MemoryStream(file))
{
zip.AddEntry("invoice" + id + ".pdf", stream);
}
Try this:
HTML:
> <a id='dwnldLnk' download='myzip.zip' style="display:none;" />
> <a ng-click="saveFile()">myzip.zip</a>
Controller:
var dataBase64 = "UEsDBAoAAAAAAORSo04AAAAAAAAAAAAAAAAEABwAc3VtL1VUCQADG7TLXKu/y1x1eAsAAQToAwAABOgDAABQSwMEFAAAAAgAe3WTTkQjafoxAAAAMgAAAAoAHABzdW0vc3VtLmdvVVQJAAM6fLlcha3LXHV4CwABBOgDAAAE6AMAACtITM5OTE9VKC7N5eJKK81LVgguzS3WSNRJUsjMK9EEEdVcnEWpJaVFeQqJ2klctQBQSwMEFAAAAAgAtkqWTksgx3NnAgAAPgQAAAcAHABtYWluLmdvVVQJAAM4Jb1cha3LXHV4CwABBOgDAAAE6AMAAHVTX0/bMBB/Jp/i5KeUlWTjkYmHDKiIxtKJlCGEeHCTS2qR2JntECrEd99dmm6VJvJi2b77/TsnPg7gGG5UgdphCd6A3yAknSxoyU3lB2kRFqbXpfTKaAiTfDED2qIFoxGMhdZYZJTCaG/Vuvd01uwQQdYWsUXtXQSQI47w2XKVXlxBpRqEUrldE7EPym8YyG+Ug8HYZ6gISpalYmrZgNJ00O6EWKylLZWuibfbWlVvPJhBo3Ub1UUMs2In+WKvxe1wR1by+WD6ycaB4ymIOfwiHGY5jT4zVMg1YroVs6+wpe5WbkEbD73DA2h8LbDzJJV0tV2jpC7wwNlfDsrjYQIxay+pXo5OwFSHZSA9NXIvfxvvu7M4HoYhkqPiyNg63huMbyjWLL862anmpjvdoHMU1u9eWYp4vQXZkapCrklrIwce4DikcfikYrCUtq7n4KbpM8zhlP6FtpdI1g8LKDapQSQ5pLmAb0me5nMGuU9X18u7Fdwnt7dJtkqvcljewsUyu0xX6TKj3QKS7AG+p9nlHJAiIx587Sw7IJmK48RynO3+Ke0l8EPhveuwUJUqyJque1kj1OYFreZ30qFtleOxOhJYMkyjWuXH9+T+98VEcRBQzs8M1NKMgoBEGOshDI6E61tBS9V6Xsg//QAvIpgFQRzDD54oqRrk+EYp22tsGhNUvS7Gy1Da2hFo98jJ6fpJaY+2kgW+vc8+OIe34Ijoop904RsdCgYSs+CIIoKzc+p6xvADyLHoUdSGkzlhMyeTM/EE5yBGeXMQ8AkmK1HqjQzJZZT3rQu/zE9nI4rvLf9+Lnj/A1BLAQIeAwoAAAAAAORSo04AAAAAAAAAAAAAAAAEABgAAAAAAAAAEAD/QQAAAABzdW0vVVQFAAMbtMtcdXgLAAEE6AMAAAToAwAAUEsBAh4DFAAAAAgAe3WTTkQjafoxAAAAMgAAAAoAGAAAAAAAAQAAAP+BPgAAAHN1bS9zdW0uZ29VVAUAAzp8uVx1eAsAAQToAwAABOgDAABQSwECHgMUAAAACAC2SpZOSyDHc2cCAAA+BAAABwAYAAAAAAABAAAA/4GzAAAAbWFpbi5nb1VUBQADOCW9XHV4CwABBOgDAAAE6AMAAFBLBQYAAAAAAwADAOcAAABbAwAAAAA="
var dataFile = 'data:application/zip;base64,' + dataBase64
var dlnk = document.getElementById('dwnldLnk');
dlnk.href = dataFile;
dlnk.click();
Actually, I have saved a file in BinaryData in Sql and now I am able to download that file by converting the BinaryData into Bytes.
My code is :
object value = (sender as DevExpress.Web.ASPxGridView.ASPxGridView).GetRowValues(e.VisibleIndex, "ID");
Int64 FileID = Convert.ToInt64(value);
var filedata = (from xx in VDC.SURVEY_QUESTION_REPLIES
where xx.ID == FileID
select xx).FirstOrDefault();
string fileextension = filedata.FILE_EXTENSION.ToString();
string fileName = filedata.ANSWER_TEXT.ToString() + fileextension;
string DocumentName = null;
FileStream FStream = null;
BinaryWriter BWriter = null;
byte[] Binary = null;
const int ChunkSize = 100;
int SizeToWrite = 0;
MemoryStream MStream = null;
DocumentName = fileName;
FStream = new FileStream(#"c:\\" + DocumentName, FileMode.OpenOrCreate, FileAccess.Write);
BWriter = new BinaryWriter(FStream);
Binary = (filedata.FILE_DATA) as byte[];
SizeToWrite = ChunkSize;
MStream = new MemoryStream(Binary);
for (int i = 0; i < Binary.GetUpperBound(0) - 1; i = i + ChunkSize)
{
if (i + ChunkSize >= Binary.Length) SizeToWrite = Binary.Length - i;
byte[] Chunk = new byte[SizeToWrite];
MStream.Read(Chunk, 0, SizeToWrite);
BWriter.Write(Chunk);
BWriter.Flush();
}
BWriter.Close();
FStream.Close();
FStream.Dispose();
System.Diagnostics.Process.Start(#"c:\" + DocumentName);
and it is directly saving the file to the location C Drive.
Now,My Requirement is that,I need to get a Prompt for saving that file and user need to select the location of saving.
Is that Possible ?
You create a filestream with a fixed location here:
FStream = new FileStream(#"c:\\" + DocumentName, FileMode.OpenOrCreate, FileAccess.Write);
What you would have to do is something like this:
var dialog = new SaveFileDialog();
if (dialog.ShowDialog() == DialogResult.OK)
{
FStream = new FileStream(dialog.FileName, FileMode.OpenOrCreate, FileAccess.Write);
// put the rest of your file saving code here
}
Remember to import the Forms namespace
using System.Windows.Forms;
If its Forms app You can use SaveFileDialog class
it is possible,
you can use a saveFileDialog that you create in your designer and call the "show" method to open that dialog :
private void button1_Click(object sender, System.EventArgs e)
{
Stream myStream ;
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*" ;
saveFileDialog1.FilterIndex = 2 ;
saveFileDialog1.RestoreDirectory = true ;
if(saveFileDialog1.ShowDialog() == DialogResult.OK)
{
if((myStream = saveFileDialog1.OpenFile()) != null)
{
// Code to write the stream goes here.
myStream.Close();
}
}
}
Source : http://msdn.microsoft.com/en-gb/library/system.windows.forms.savefiledialog.aspx
I see that you use web components of DevExpress, so assuming that you want to send the stream to response for the client to save the file.
If it is an ASP.NET MVC application, you can return FileContentResult as action result directly. Otherwise, you might use the following sample adapting into your code
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment; filename=" + DocumentName);
MStream.WriteTo(Response.OutputStream);
Depending on user's browser settings, save file dialog might be shown to the user.