I'm calling a routine in PHP (TCPDF) from C# via WebRequest using StreamReader. The PDF file is returned as a stream and stored in a string (obv). I know the data being returned to the string is actually a PDF file, as I've tested it in PHP. I'm having a hard time writing the string to a file and actually getting a valid PDF in C#. I know it has something to do with the way I'm trying to encode the file, but the several things I've tried have resulted in 'Not today, Padre' (i.e. they didn't work)
Here's the class I'm using to perform the request (thanks to user 'Paramiliar' for the example I'm using/borrowed/stole):
public class httpPostData
{
WebRequest request;
WebResponse response;
public string senddata(string url, string postdata)
{
// create the request to the url passed in the paramaters
request = (WebRequest)WebRequest.Create(url);
// set the method to POST
request.Method = "POST";
// set the content type and the content length
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = postdata.Length;
// convert the post data into a byte array
byte[] byteData = Encoding.UTF8.GetBytes(postdata);
// get the request stream and write the data to it
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteData, 0, byteData.Length);
dataStream.Close();
// get the response
response = request.GetResponse();
dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
// read the response
string serverresponse = reader.ReadToEnd();
//Console.WriteLine(serverresponse);
reader.Close();
dataStream.Close();
response.Close();
return serverresponse;
}
} // end class httpPostData
...and my call to it
httpPostData myPost = new httpPostData();
// postData defined (not shown)
string response = myPost.senddata("http://www.example.com/pdf.php", postData);
In case it isn't clear, I'm stuck writing string response to a valid .pdf file. I've tried this (Thanks to user Adrian):
static public void SaveStreamToFile(string fileFullPath, Stream stream)
{
if (stream.Length == 0) return;
// Create a FileStream object to write a stream to a file
using (FileStream fileStream = System.IO.File.Create(fileFullPath, (int)stream.Length))
{
// Fill the bytes[] array with the stream data
byte[] bytesInStream = new byte[stream.Length];
stream.Read(bytesInStream, 0, (int)bytesInStream.Length);
// Use FileStream object to write to the specified file
fileStream.Write(bytesInStream, 0, bytesInStream.Length);
}
}
..and the call to it:
string location = "C:\\myLocation\\";
SaveStreamToFile(location, response); // <<-- this throws an error b/c 'response' is a string, not a stream. New to C# and having some basic issues with things like this
I think I'm close...a nudge in the right direction would be greatly appreciated.
You can use WebClient. Use the method DownloadFile, or the async ones.
Have fun!
Fernando.-
Sorry, I haven't read your comments till now.
I guess you have already done this...
But this may help you (just replace urls and paths) (from: http://msdn.microsoft.com/en-us/library/ez801hhe.aspx )
string remoteUri = "http://www.contoso.com/library/homepage/images/";
string fileName = "ms-banner.gif", myStringWebResource = null;
// Create a new WebClient instance.
WebClient myWebClient = new WebClient();
// Concatenate the domain with the Web resource filename.
myStringWebResource = remoteUri + fileName;
Console.WriteLine("Downloading File \"{0}\" from \"{1}\" .......\n\n", fileName, myStringWebResource);
// Download the Web resource and save it into the current filesystem folder.
myWebClient.DownloadFile(myStringWebResource,fileName);
Console.WriteLine("Successfully Downloaded File \"{0}\" from \"{1}\"", fileName, myStringWebResource);
Console.WriteLine("\nDownloaded file saved in the following file system folder:\n\t" + Application.StartupPath);
Related
I can't use WebClient, before anyone suggests that because it makes my legit application seem like a virus to McAfee. So please don't suggest that.
I have a binary.txt file stored on my server. It is approximately 1,240kb. However, HttpWebRequest downloads random amounts from 1,300kb to 1,700kb.
HttpWebRequest httpRequest = (HttpWebRequest)
WebRequest.Create("http://deviantsmc.com/binary.txt");
httpRequest.Method = WebRequestMethods.Http.Get;
HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();
Stream httpResponseStream = httpResponse.GetResponseStream();
byte[] buffer = new byte[1240];
int bytesRead = 0;
StringBuilder sb = new StringBuilder();
//FileStream fileStream = File.Create(#"tcontent.txt");
while ((bytesRead = httpResponseStream.Read(buffer, 0, 1240)) != 0)
{
sb.Append(Encoding.ASCII.GetString(buffer));
//fileStream.Write(buffer, 0, bytesRead);
}
File.WriteAllText(#"tcontent1.txt", sb.ToString());
(The contents of the binary.txt file on the server are in ASCII, therefore I get the Encoding string to ASCII as well).
This is how I encoded that text file (on that server)
My file is basically this:
byte[] bytes = File.ReadAllBytes("binary.txt");
String encBytes = Encoding.ASCII.GetString(bytes);
File.WriteAllText(file("binary.txt"), encBytes);
I contacted the AV company about the WebDownloader being seen as some malicious import in C#, but they didn't get back to me, so I'm forced to use HttpWebRequest.
If your only goal is to fetch that binary and write it to disk you can simply copy the stream to a file with the CopyTo method that exists on a Stream object.
Your file looks like a broken zip file btw, given the first characters that are PK, and is used in the zip specificaton.
From wikipedia:
Viewed as an ASCII string this reads "PK", the initials of the inventor Phil Katz. Thus, when a .ZIP file is viewed in a text editor the first two bytes of the file are usually "PK".
I used 7-zip to open your file as the Windows default didn't accept it as a valid file. It contains a manifest.mf file but the content itself seems missing. the file itself has a size of 1.269.519 bytes.
HttpWebRequest httpRequest = (HttpWebRequest)
WebRequest.Create("http://deviantsmc.com/binary.txt");
httpRequest.Method = WebRequestMethods.Http.Get;
HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();
Stream httpResponseStream = httpResponse.GetResponseStream();
// create and open a FileStream, using calls dispose when done
using(var fs= File.Create(#"c:\temp\bin.7z"))
{
// Copy all bytes from the responsestream to the filestream
httpResponseStream.CopyTo(fs);
}
I think you should write the entire binary data to the local file, instead of encoding it segmentally, you can try this:
HttpWebRequest httpRequest = (HttpWebRequest)
WebRequest.Create("http://deviantsmc.com/binary.txt");
httpRequest.Method = WebRequestMethods.Http.Get;
HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();
Stream httpResponseStream = httpResponse.GetResponseStream();
using (BinaryReader responseReader = new BinaryReader(httpResponseStream.GetResponseStream()))
{
byte[] bytes = responseReader.ReadBytes((int)response.ContentLength);
using (BinaryWriter sw = new BinaryWriter(File.OpenWrite("tcontent1.txt")))
{
sw.Write(bytes);
sw.Flush();
sw.Close();
}
}
Hope this can help
I am trying to use an API and I don't have any problems with GET and POST but PUT isn't working. I tried with a lot of different examples and finally by chance I discovered that waiting more that 5 seconds (with 5000ms it is not working and with 5100ms it does) it starts working properly. But why is that happening? And how can I avoid this? 5 seconds for each registry update is to much waiting and I really don't understand why POST works well without waiting and PUT needs 5 seconds to work.
Here I put the method that I am using with the Thread.Sleep(5100). As I said without this line when I make WebResponse response = request.GetResponse(); gives me an error.
public void call(string url, object jsonObj)
{
try
{
// Create a request using a URL that can receive a post.
HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(urlSplio);
// Create POST data and convert it to a byte array.
request.Method = "PUT";
// Set the ContentType property of the WebRequest.
request.ContentType = "application/json";
request.Credentials = new NetworkCredential(WebConfigurationManager.AppSettings["User"], "WebConfigurationManager.AppSettings["Key"]");
string json = JsonConvert.SerializeObject(jsonObj);
byte[] byteArray = Encoding.UTF8.GetBytes(json);
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
// Get the request stream.
Stream dataStream = request.GetRequestStream();
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Close();
Thread.Sleep(5100);
// Get the response.
WebResponse response = request.GetResponse();
// Display the status.
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
// 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.
dataStream.Close();
response.Close();
}
catch (Exception ex)
{
}
}
I think you might want to rewrite the response stream code
Take a look at this walkthrough on MS MS walkthrough
private byte[] GetURLContents(string url)
{
// The downloaded resource ends up in the variable named content.
var content = new MemoryStream();
// Initialize an HttpWebRequest for the current URL.
var webReq = (HttpWebRequest)WebRequest.Create(url);
// Send the request to the Internet resource and wait for
// the response.
// Note: you can't use HttpWebRequest.GetResponse in a Windows Store app.
using (WebResponse response = webReq.GetResponse())
{
// Get the data stream that is associated with the specified URL.
using (Stream responseStream = response.GetResponseStream())
{
// Read the bytes in responseStream and copy them to content.
responseStream.CopyTo(content);
}
}
// Return the result as a byte array.
return content.ToArray();
}
what im trying to do is to make photo upload to imgur site using their API here http://api.imgur.com/endpoints/image#image-upload. As i read in documentation, image data has to be in "image" parameter. So what im doing is setting POST request data as "image=base64codedfile&title=blabla&type=base64" and it does upload it but file is corrupted. If my request will contain only "base64codedfile" without image, title, type name parameters its working like a charm. Am i doing something wrong?
If i set it as:
string postData = "image="+Convert.ToBase64String(image)+"&type=base64&title=test;
image is corrupted
If it's only raw data:
string postData = Convert.ToBase64String(image);
It's working
Whole code is something like this:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://api.imgur.com/3/upload.xml");
request.Headers.Add("Authorization", "Client-ID >>myclientid<<");
request.Method = "POST";
string filePath = "d:\\test.jpg";
FileStream file = new FileStream(filePath, FileMode.Open);
byte[] image = new byte[file.Length];
file.Read(image, 0, (int)file.Length);
ASCIIEncoding enc = new ASCIIEncoding();
string postData = Convert.ToBase64String(image);
byte[] bytes = enc.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = bytes.Length;
Stream writer = request.GetRequestStream();
writer.Write(bytes, 0, bytes.Length);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
I am also trying to do the same and also facing the problem...
I got one solution...
After uploading your image get the id of the image using response.getresponsestream()....
then using this id update that image..and dont forget to use imgur api to update image..to know more about updating imgur image visit this link.
My solution :
using (var reader = new StreamReader(response.GetResponseStream()))
{
var objText = reader.ReadToEnd();
}
in object text you will found the json response
For the first time, I am having to use a vendor's API by posting an XML dataset to a URL. If I encode the dataset using http://meyerweb.com/eric/tools/dencoder/, and manually paste the URL & dataset into a browser, I get a successful response.
However, when trying to do the same thing with .NET, I get a response from the vendor API indicating that my dataset is invalid.
Here's my code (which I copied from elsewhere on the good ol' interweb):
public void PostXML(string value1, string value2, string value3, out string responseStatus, out string responseBody)
{
// Create a request using a URL that can receive a post.
WebRequest request = WebRequest.Create("https://www.vendorURL.com/API/page.html?input=");
// Set the Method property of the request to POST.
request.Method = "POST";
// Create POST data and convert it to a byte array.
string postData = "<DATASET>";
postData += "<FIELD1>" + value1+ "</FIELD1>";
postData += "<FIELD2>" + value2 + "</FIELD2>";
postData += "<FIELD3>" + value3 + "</FIELD3>";
postData += "</DATASET>";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Set the ContentType property of the WebRequest.
request.ContentType = "application/x-www-form-urlencoded";
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
// Get the request stream.
Stream dataStream = request.GetRequestStream();
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Close();
// Get the response.
WebResponse response = request.GetResponse();
// Assign the status.
responseStatus = ((HttpWebResponse)response).StatusDescription;
// 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.
responseBody = reader.ReadToEnd();
// Clean up the streams.
reader.Close();
dataStream.Close();
response.Close();
}
Keep in mind, I am getting a response from the vendor API. It's just telling me that my dataset is invalid. I have already contacted the vendor's customer support. That have confirmed that my dataset itself is correct, but somewhere along the way I'm encoding it incorrectly for it to be recognizable by the vendor API.
Several things are missing.
You should probably start with an xml declaration
<?xml version="1.0"?>
Also are you sure the dataset tags are upper case? Case is significant in Xml.
<?xml version="1.0"?>
<dataset><field>value</field></dataset>
Additionally you might try XmlWriter:
using(var writer = XmlWriter.Create(stream))
{
writer.WriteStartDocument();
writer.WriteStartElement("dataset");
writer.WriteElementString("field1", "value");
writer.WriteElementString("field2", "value");
writer.WriteElementString("field3", "value");
writer.WriteEndElement();
writer.WriteEndDocument();
}
Finally contact the vendor to send you sample code/API...
Try using System.Web.HttpUtility.UrlEncode on your post data before invoking "Encoding.UTF8.GetBytes(postData);".
I want to create a file with a .aspx extension(or any other extension) completely in memory. Can this be done?
Right now I have a memory stream that has all the stuff I want to write to this file but I don't actually want to create a physical file on the server since then I probably have to enable write permissions for my server. What I want to do is create the file in memory and upload via ftpWebRequest.
Edit.
I must be doing something wrong because I get weird stuff in my file so weird I can't even paste it into my posts.
Basically it is a bunch of squares between everything. Like it almost seems like it fills it in for the spaces. Like If I look closely I will see the tag still but it will have a square between each letter.
Here is a portion of my code. Maybe I am using the wrong encoding?
using (MemoryStream memory = new MemoryStream())
{
UnicodeEncoding uniEncoding = new UnicodeEncoding();
// readByline is the first bunch of data I want for my new file.
memory.Write(uniEncoding.GetBytes(readByLine), 0, readByLine.Length);
// second bunch of data I want for my new file.
memory.Write(uniEncoding.GetBytes(html), 0, html.Length);
// the follow code just figure out the end of the file that I am
// trying to extract some information out of.
string readToEnd = reader.ReadToEnd();
int endIndex = readToEnd.IndexOf(END_FLAG);
endIndex += END_FLAG.Length;
string restOfFile = readToEnd.Substring(endIndex);
// once found I write it the memory stream.
memory.Write(uniEncoding.GetBytes(restOfFile),0,restOfFile.Length);
// now I want to upload my file. I have the same file name already
// existing on the server? Do I have to tell it override it?
FtpWebRequest request2 = (FtpWebRequest)WebRequest.Create(path);
request2.Method = WebRequestMethods.Ftp.UploadFile;
request2.Credentials = new NetworkCredential(ftpUsername, ftpPassword);
// now I am trying your code.
byte[] fileContents = memory.ToArray();
using (Stream writer = request2.GetRequestStream())
{
writer.Write(fileContents, 0, fileContents.Length);
}
FtpWebResponse test = (FtpWebResponse)request2.GetResponse();
return Content("test");
}
You can convert the MemoryStream to a byte[] and then use WebClient.UploadData to upload the file with FTP to some server without writing it on the client to disk first:
webClient.UploadData(
"ftp://remoteserver/remotepath/file.aspx"
memoryStream.ToArray());
FtpWebRequest works as well, of course, but needs a few more lines of code:
FtpWebRequest ftpRequest;
FtpWebResponse ftpResponse;
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://..."));
ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
ftpRequest.Proxy = null;
ftpRequest.UseBinary = true;
ftpRequest.Credentials = new NetworkCredential("UserName", "Password");
using (Stream stream = ftpRequest.GetRequestStream())
using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8))
{
writer.WriteLine("<html><head><title>Hello World</title></head>...");
}
ftpResponse = (FtpWebResponse)ftpRequest.GetResponse();
Well, such a file is really just plain text, with certain formatting - HTML 4.0, XHTML or such.
So yes, you can create that in memory - inside e.g. a StringBuilder, and then save it back out to disk using a StreamWriter or some other means.
If you can't or don't want to write it out to disk, you can of course also put it into a MemoryStream, and interfaces that can read from any arbitrary stream can read from the memory stream, too.
Check out the MSDN docs on FtpWebRequest and on GetRequestStream() method. It has a sample on how to upload from a stream to FTP directly:
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(serverUri);
request.Method = WebRequestMethods.Ftp.UploadFile;
// this could be your MemoryStream, of course, that you're reading from
StreamReader sourceStream = new StreamReader(fileName);
byte[] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
sourceStream.Close();
request.ContentLength = fileContents.Length;
request.Credentials = new NetworkCredential(ftpUsername, ftpPassword);
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
requestStream.Close();
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
// check the response, do whatever you need to do with it
response.Close();