I have a very simple piece of code.
Everything is correctly written, no typos, and i chattet with a coworker but both of us have simply no idead where the error lies in here.
It smoothly goes through undtil the GetRequestStream() where the exception pops up. It finds the files, encodes it correctly but then can't seem to connect with the server.
This is the code:
public class WebRequestUploadExample
{
public void WebRequestUpload()
{
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(#"ftp://xxxxx");
request.Method = WebRequestMethods.Ftp.UploadFile;
// This example assumes the FTP site uses anonymous logon.
request.Credentials = new NetworkCredential("xxxxx", "xxxxx");
// Copy the contents of the file to the request stream.
StreamReader sourceStream = new StreamReader(#"D:\ftpTest\Test\Test.txt");
byte[] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
sourceStream.Close();
request.ContentLength = fileContents.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
requestStream.Close();
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Console.WriteLine("Upload File Complete, status {0}", response.StatusDescription);
response.Close();
}
}
May be your target server does not support 'passive' mode. Have you tried active-mode? request.UsePassive = false;
FtpWebRequest.UsePassive
Related
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();
}
This question already has answers here:
"Requested URI is invalid" during upload with FtpWebRequest
(2 answers)
Closed 8 years ago.
I need to copy some txt files to ftp server from local machine. I used following code. (took from : http://msdn.microsoft.com/en-us/library/ms229715(v=vs.110).aspx)
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://ftp.xxxx.com/");
request.Method = WebRequestMethods.Ftp.UploadFile;
// This example assumes the FTP site uses anonymous logon.
request.Credentials = new NetworkCredential("username", "paswword");
// Copy the contents of the file to the request stream.
StreamReader sourceStream = new StreamReader(#"E:\log.txt");
byte [] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
sourceStream.Close();
request.ContentLength = fileContents.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
requestStream.Close();
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Console.WriteLine("Upload File Complete, status {0}", response.StatusDescription);
response.Close();
}
but i cause "The requested URI is invalid for this FTP command" error. How could I solve that???
You missing file name at URI. For example:
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://ftp.xxxx.com/log.txt");
Take a good look at example you using. Note test.htm?
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://www.contoso.com/test.htm");
I'm trying to understand the MSDN documentation for FtpWebRequest and more specificaly, how to upload using FTP and C#
using System;
using System.IO;
using System.Net;
using System.Text;
namespace Examples.System.Net
{
public class WebRequestGetExample
{
public static void Main ()
{
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://www.contoso.com/test.htm");
request.Method = WebRequestMethods.Ftp.UploadFile;
// This example assumes the FTP site uses anonymous logon.
request.Credentials = new NetworkCredential ("anonymous","janeDoe#contoso.com");
// Copy the contents of the file to the request stream.
StreamReader sourceStream = new StreamReader("testfile.txt");
byte [] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
sourceStream.Close();
request.ContentLength = fileContents.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
requestStream.Close();
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Console.WriteLine("Upload File Complete, status {0}", response.StatusDescription);
response.Close();
}
}
}
}
In the code above they reference 2 file types. Am I right in assuming that testfile.txt is the 'source' file (on the local computer) and test.htm is what testfile.txt will be renamed too?
Yes - you're uploading to test.htm, loading the data from testfile.txt. You can tell that because test.htm is part of the URL (so is remote) whereas testfile.txt is loaded by just creating a StreamReader over a file.
(It's worth noting that this code is pretty bad in various ways, by the way - particularly around resource disposal. Don't treat it as embodying best practices...)
I am trying to send contents of 1GB text file over the network. I modified the suggested code for basic authentication and kept it as follows :
WRequest = (HttpWebRequest)HttpWebRequest.Create(URL);
WRequest.Credentials = Credentials;
WRequest.PreAuthenticate = true;
WRequest.ContentType = "text/plain";
WRequest.Method = "POST";
WRequest.AllowWriteStreamBuffering = false;
WRequest.Timeout = 10000;
FileStream ReadIn = new FileStream(filename, FileMode.Open, FileAccess.Read);
ReadIn.Seek(0, SeekOrigin.Begin);
WRequest.ContentLength = ReadIn.Length;
Byte[] FileData = new Byte[ReadIn.Length];
int DataRead = 0;
Stream tempStream = WRequest.GetRequestStream();
do
{
DataRead = ReadIn.Read(FileData, 0, 2048);
if (DataRead > 0)
{
tempStream.Write(FileData, 0, DataRead);
Array.Clear(FileData, 0, 2048);
}
} while (DataRead > 0);
// The response
WResponse = (HttpWebResponse)WRequest.GetResponse();
However, now it gives me System.Net.ProtocolViolationException error : "You must write ContentLength bytes to the request stream before calling [Begin]GetResponse". I checked HttpWebRequest.BeginGetRequestResponse ... and found from debugging that the contentlength for WRequest is not -1. What else could be going wrong ? How should I get the response ?
Update :
The code which worked for small files is as followed :
WebRequest request = WebRequest.Create(url);
request.Method = "POST";
request.Credentials = Credentials;
using (StreamReader reader = new StreamReader(filename))
{
postData = reader.ReadToEnd();
}
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "text/plain";
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
// The response
WebResponse response = request.GetResponse();
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
dataStream = response.GetResponseStream();
using (StreamReader reader = new StreamReader(dataStream))
{
responseFromServer = reader.ReadToEnd();
}
dataStream.Close();
response.Close();
The article you referenced says
If the Microsoft Internet Information Services (IIS) Web server is configured to use Basic authentication, and you must set the HttpWebRequest.AllowWriteStreamBuffering property to false, you must send a HEAD request to pre-authenticate the connection before you send the POST or PUT request.
EDIT - now with more clarification!
To restate the article, if you want to send a large file to a destination which requires basic authentication, you'll need to issue two separate requests. The key here is that you are setting PreAuthenticate = true. Read the statement literally -- by setting the property to true, you are saying that you will authenticate any requests that you make before you actually attempt them! The framework doesn't know how you want to accomplish this pre-authentication, so you need to perform that action yourself, by sending a HEAD request to the destination. Think of the HEAD HTTP method as being a prologue to the actual request - it describes (or requests information about) a particular resource.
So the process goes like this:
Make a HEAD request to http://someurl/aresource containing the credentials you want to use when making future requests from this client to that server for the listed resource
The server will respond (ideally) with "OK - you may proceed. You're authenticated"
The server immediately regrets its' decision to allow the operation as it finds itself saving a very large file :-)
I don't see you making that HEAD request anywhere in the code you posted - if it's not already there, add this at the beginning of your code (snipped from the sample article ref in OP):
//preAuth the request
// You can add logic so that you only pre-authenticate the very first request.
// You should not have to pre-authenticate each request.
WRequest = (HttpWebRequest)HttpWebRequest.Create(URL);
// Set the username and the password.
WRequest.Credentials = new NetworkCredential(user, password);
WRequest.PreAuthenticate = true;
WRequest.UserAgent = "Upload Test";
WRequest.Method = "HEAD";
WRequest.Timeout = 10000;
WResponse = (HttpWebResponse)WRequest.GetResponse();
WResponse.Close();
// Make the real request.
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();