I have been assigned to take over someones position, however I do not really know C#. There is a server (192.268. something ect) that will post data to a site (unknown site, lets say bleh.com)
This is what the posting code snippet looks like:
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(
"https://server-ip-here/postlistener?filename=filename.zlib");
req.UseNagleAlgorithm = true;
req.AllowWriteStreamBuffering = true;
req.Method = "POST";
req.Accept = "application/xml";
req.ServicePoint.Expect100Continue = false;
System.Net.ServicePointManager.CheckCertificateRevocationList = false;
req.Proxy = new WebProxy();
filename = "filename.dat";
byte[] postData = File.ReadAllBytes(filename);
Stream stream = req.GetRequestStream();
stream.Write(postData, 0, postData.Length);
stream.Flush();
stream.Close();
req.BeginGetResponse(new AsyncCallback(responseHandler), this);
Which I beleive I get the post request in this form
www.blah.com/upload?filename=file_1234_12389126495129847980.zlib
I am unsure how to listen for post requests and then get the data from them and save them as a file.
Currently I have tried this:
private void Form1_Load(object sender, EventArgs e)
{
listener = new HttpListener();
// listener.Prefixes.Add("http://localhost:8000/");
listener.Prefixes.Add("http://127.0.0.1:8000/");
listener.AuthenticationSchemes = AuthenticationSchemes.Anonymous;
listener.Start();
listenThread1 = new Thread(new ParameterizedThreadStart(startlistener));
listenThread1.Start();
}
private void startlistener(object s)
{
while (true)
{
// blocks until a client has connected to the server
ProcessRequest();
}
}
private void ProcessRequest()
{
var result = listener.BeginGetContext(ListenerCallback, listener);
result.AsyncWaitHandle.WaitOne();
}
private void ListenerCallback(IAsyncResult result)
{
var context = listener.EndGetContext(result);
Thread.Sleep(1000);
var data_text = new StreamReader(
context.Request.InputStream,
context.Request.ContentEncoding).ReadToEnd();
var cleaned_data = System.Web.HttpUtility.UrlDecode(data_text);
context.Response.StatusCode = 200;
context.Response.StatusDescription = "OK";
MessageBox.Show(cleaned_data);
context.Response.Close();
}
Which listens on the local host (Would sub local host for the website once we establish what it will be).
Not sure how to grab the post though, right now I can only listen for it. Ideally I would only like to accept posts from a specific IP address also.
Any ideas how I can go about grabbing the post data (which will be binary) and saving it as a file?
I have the following code to download some files from a FTP Server :
EDIT : I've solved the problem using DotNet, a good FTP WPF Library !
public partial class MainWindow
{
DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
private byte[] downloadedData;
string FTPAddress = "ftp://ftp.cluster007.ovh.net";
double currentBytes;
double oldBytes;
public MainWindow()
{
InitializeComponent();
// DispatcherTimer setup
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
}
public static void DoEvents()
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background,
new Action(delegate { }));
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
currentBytes = Dl_ProgressBar.Value;
Dl_Speed.Content = "Vitesse : " + ((currentBytes - oldBytes) / 1000000).ToString("0.00") + " Mo/s";
oldBytes = Dl_ProgressBar.Value;
// Forcing the CommandManager to raise the RequerySuggested event
CommandManager.InvalidateRequerySuggested();
}
private void Dl_Button_Click(object sender, RoutedEventArgs e)
{
downloadFile();
}
private void downloadFile()
{
downloadedData = new byte[0];
try
{
//Create FTP request
//Note: format is ftp://server.com/file.ext
FtpWebRequest request = FtpWebRequest.Create(FTPAddress + "/" + filename) as FtpWebRequest;
//Get the file size first (for progress bar)
request.Method = WebRequestMethods.Ftp.GetFileSize;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = true; //don't close the connection
int dataLength = (int)request.GetResponse().ContentLength;
Dl_Status.Content = "Téléchargement en cours...";
DoEvents();
//Now get the actual data
request = FtpWebRequest.Create(FTPAddress + "/" + filename) as FtpWebRequest;
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false; //close the connection when done
//Set up progress bar
Dl_ProgressBar.Value = 0;
Dl_ProgressBar.Maximum = dataLength;
//Streams
FtpWebResponse response = request.GetResponse() as FtpWebResponse;
Stream reader = response.GetResponseStream();
//Download to memory
//Note: adjust the streams here to download directly to the hard drive
MemoryStream memStream = new MemoryStream();
byte[] buffer = new byte[1024]; //downloads in chuncks
dispatcherTimer.Start();
while (true)
{
DoEvents(); //prevent application from crashing
int bytesRead = reader.Read(buffer, 0, buffer.Length);
if (bytesRead == 0)
{
//Nothing was read, finished downloading
Dl_ProgressBar.Value = Dl_ProgressBar.Maximum;
Dl_Percent.Content = "Progression : 100%";
DoEvents();
break;
}
else
{
//Write the downloaded data
memStream.Write(buffer, 0, bytesRead);
//Update the progress bar
if (Dl_ProgressBar.Value + bytesRead <= Dl_ProgressBar.Maximum)
{
Dl_ProgressBar.Value += bytesRead;
Dl_Percent.Content = "Progression : " + ((Dl_ProgressBar.Value / 1000000000000000) * dataLength).ToString("0.00") + "%";
DoEvents();
}
}
}
//Convert the downloaded stream to a byte array
downloadedData = memStream.ToArray();
//Clean up
reader.Close();
memStream.Close();
response.Close();
Dl_Status.Content = "Téléchargement terminé";
DoEvents();
}
catch (Exception)
{
Dl_Status.Content = "Erreur de connexion au FTP";
}
}
}
My problem is that when I pass the mouse over the window, the download speed is dropping significantly...
It changes from 3.70Mb/s to 2.20Mb/s.
When I have the mouse out of the window, there's no problem, but when I'm over it, it slows down, particularly when I do some very short movements, the download speed go to 0.20Mb/s.
I've tried to use Threads and Dispatcher but it was the same.
To answer your specific question, WPF's Dispatcher uses a priority queue, and Input level events (like those originating from mouse movement) take priority over Background level events. Your DoEvents() method periodically drains the message queue of all events with Background priority or higher, so when you move the mouse over the window, the queue fills up with input events to process. This means that DoEvents takes longer to return, and more time elapses before you can resume processing the download.
That said, this is a terrible way to accomplish a download; you should never use this kind of DoEvents() hack in WPF; do some research on the async and await features of C# (or, if that is not an option, BackgroundWorker). You will find many examples on StackOverflow of how to perform asynchronous downloads without having to resort to this sort of Dispatcher trickery to keep the UI responsive.
I have code set up to do an FTP PUT with a file to an FTP server. First I have a method that checks if the file exists at the target location. Then if it does I have another method that deletes the file. Then I perform the FTP PUT to the target location.
Currently, I'm performing these 3 methods by setting up 3 separate FTP connections to the same server. However, I want to perform all 3 methods with one connection to the server. The reason is because I'm getting the following error after opening multiple connections to same FTP server: "An existing connection was forcibly closed by the remote host."
Here are the 3 functions below. The first method, GetFileFromRemoteServer, is used to see if a file exists on the FTP server at target path. I use regex in some cases to get partial name match, or in other cases just do full name match.
I researched online that someone said it's possible to use the same ftp request object and just perform all methods you want and then close the connection. I tried to see if it works performing multiple methods on same request object and I got this error: This operation cannot be performed after the request has been submitted.
Is there a way to perform all of them using one connection to the server?
Thank you, I really appreciate your help!
public static List<FTPLineResult> GetFileFromRemoteServer(bool isSsl, string username, string password, string fileName, string dir, Regex regexPattern,
bool getSingleFile = false)
{
var output = new List<FTPLineResult>();
var parser = new FTPLineParser();
var isDone = false;
var request = (FtpWebRequest)WebRequest.Create(dir);
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
request.ConnectionGroupName = ConfigurationManager.AppSettings["ftpConnectionGroup"];
request.KeepAlive = true;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = true;
if (isSsl)
{
request.EnableSsl = true;
}
else
{
request.EnableSsl = false;
}
using (var response = (FtpWebResponse)request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
using (var reader = new StreamReader(responseStream, Encoding.ASCII))
{
while (!isDone && !reader.EndOfStream)
{
var result = parser.Parse(reader.ReadLine());
//if "*" is in file name, which means get partial match, replacing * with real file name content
if (regexPattern != null)
{
if (regexPattern.IsMatch(result.Name.ToLower().Trim()))
{
output.Add(result);
}
}
else if (result.Name.ToLower().Trim() == fileName.ToLower().Trim())
{
output.Add(result);
isDone = true;
}
}
return output;
}
}
}
}
private void DeleteExistingTargetFile()
{
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(_params.FinalFolderTarget);
request.Method = WebRequestMethods.Ftp.DeleteFile;
request.Credentials = new NetworkCredential(_params.Username, _params.Password);
request.UsePassive = true;
request.ConnectionGroupName = ConfigurationManager.AppSettings["ftpConnectionGroup"];
request.KeepAlive = true;
if (_params.IsSsl)
{
request.EnableSsl = true;
}
else
{
request.EnableSsl = false;
}
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
{
var status = response.StatusDescription;
}
}
private void DoFtpPut(Dictionary<StatusEnum, string> statusDict)
{
int buffLength = 2048;
byte[] buff = new byte[buffLength];
System.IO.FileInfo _FileInfo = new System.IO.FileInfo(_params.SourceFilename);
var request = (FtpWebRequest)WebRequest.Create(new Uri(_params.TargetFilename));
request.Method = WebRequestMethods.Ftp.UploadFile;
request.ConnectionGroupName = ConfigurationManager.AppSettings["ftpConnectionGroup"];
request.KeepAlive = true;
request.Credentials = new NetworkCredential(_params.Username, _params.Password);
request.UsePassive = true;
if (_params.IsSsl)
{
request.EnableSsl = true;
}
else
{
request.EnableSsl = false;
}
using (var _Stream = request.GetRequestStream())
{
//read file one chunk at a time in order to avoid out of memory exception
using (var fileStream = _FileInfo.OpenRead())
{
var contentLen = fileStream.Read(buff, 0, buffLength);
while (contentLen != 0)
{
_Stream.Write(buff, 0, contentLen);
contentLen = fileStream.Read(buff, 0, buffLength);
}
}
}
statusDict[StatusEnum.ftpStatus] = Constants.SUCCESS_STATUS;
}
I couldn't figure out a way to do FTPPUT with only one connection using FtpWebRequest class. However, using FtpLib library allowed me to do exactly what I wanted, which was to check if file exists on ftp server target location, if it does then delete it, and then do ftp put, and finally move file to final location using a rename.
Here's where I downloaded ftplib library: ftplib.codeplex.com
Here's the code below:
using (FtpConnection ftp = new FtpConnection(host, _params.Username, _params.Password))
{
try
{
ftp.Open(); /* Open the FTP connection */
ftp.Login(); /* Login using previously provided credentials */
ftp.PutFile(_params.SourceFilename, _params.TargetFilename); /* upload /incoming/file.txt as file.txt to current executing directory, overwrite if it exists */
if (!ftp.DirectoryExists(_params.FinalDir)) /* check that a directory exists */
{
ftp.CreateDirectory(_params.FinalDir);
}
if (ftp.FileExists(_params.FinalLocation))
{
ftp.RemoveFile(_params.FinalLocation);
}
ftp.RenameFile(target, _params.FinalLocation);
statusDict[StatusEnum.ftpStatus] = Constants.SUCCESS_STATUS;
}
catch (Exception ex)
{
statusDict[StatusEnum.ftpStatus] = Constants.ERROR_STATUS;
}
}
How can I implement a FileSystemWatcher for an FTP location (in C#). The idea is whenever anything gets added in the FTP location I wish to copy it to my local machine. Any ideas will be helpful.
This is a follow up of my previous question Selective FTP download using .NET.
You're going to have to implement a polling solution, where you keep asking for the directory content periodically. Compare this to a cached list from the previous call and determine what happened that way.
There's nothing in the FTP protocol that will help you with this unfortunately.
You cannot use the FileSystemWatcher or any other way, because the FTP protocol does not have any API to notify a client about changes in the remote directory.
All you can do is to periodically iterate the remote tree and find changes.
It's actually rather easy to implement, if you use an FTP client library that supports recursive listing of a remote tree. Unfortunately, the built-in .NET FTP client, the FtpWebRequest does not. But for example with WinSCP .NET assembly, you can use the Session.EnumerateRemoteFiles method.
See the article Watching for changes in SFTP/FTP server:
// Setup session options
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Ftp,
HostName = "example.com",
UserName = "user",
Password = "password",
};
using (Session session = new Session())
{
// Connect
session.Open(sessionOptions);
List<string> prevFiles = null;
while (true)
{
// Collect file list
List<string> files =
session.EnumerateRemoteFiles(
"/remote/path", "*.*", EnumerationOptions.AllDirectories)
.Select(fileInfo => fileInfo.FullName)
.ToList();
if (prevFiles == null)
{
// In the first round, just print number of files found
Console.WriteLine("Found {0} files", files.Count);
}
else
{
// Then look for differences against the previous list
IEnumerable<string> added = files.Except(prevFiles);
if (added.Any())
{
Console.WriteLine("Added files:");
foreach (string path in added)
{
Console.WriteLine(path);
}
}
IEnumerable<string> removed = prevFiles.Except(files);
if (removed.Any())
{
Console.WriteLine("Removed files:");
foreach (string path in removed)
{
Console.WriteLine(path);
}
}
}
prevFiles = files;
Console.WriteLine("Sleeping 10s...");
Thread.Sleep(10000);
}
}
(I'm the author of WinSCP)
Though, if you actually want to just download the changes, it's a way easier. Just use the Session.SynchronizeDirectories in the loop.
session.SynchronizeDirectories(
SynchronizationMode.Local, "/remote/path", #"C:\local\path", true).Check();
See the article Keep local directory up to date (download changed files from remote SFTP/FTP server).
If you do not want to use a 3rd party library, you have to do with limitations of the FtpWebRequest. For an example how to recursively list a remote directory tree with the FtpWebRequest, see my answer to C# Download all files and subdirectories through FTP.
The FileSystemWatcher class works by registering for events with the host Windows operating system. As such, it is limited to working on local paths and UNC paths to directories hosted on Windows systems. The MSDN documentation on FileSystemWatcher explains the paths which you can use and some of the potential problems with using the class.
If you are looking to be alerted to changes on an FTP site, you will have to use a polling mechanism to ask for the current status of files or folders you are interested in monitoring. You will be able to see when files are added and removed by comparing snapshots of the FTP site for changes and raising similar events when you detect changes. Unfortunately you wont be able to detect rename events, but other changes should be simple to monitor this way.
Write a simple service to create FileSystemWatcher, pointing at your ftp location.
Then when a file is uploaded or modified, an event will be fired in your service, which you can then use to copy the file to your local machine.
File.Copy etc.
Hav a look at: this blog
You can monitor the FTP location by following method:
public class FtpFileSystemWatcher
{
public bool IsRunning
{
get;
private set;
}
public string FtpUserName
{
get;
set;
}
public string FtpPassword
{
get;
set;
}
public string FtpLocationToWatch
{
get;
set;
}
public string DownloadTo
{
get;
set;
}
public bool KeepOrignal
{
get;
set;
}
public bool OverwriteExisting
{
get;
set;
}
public int RecheckIntervalInSeconds
{
get;
set;
}
private bool DownloadInprogress
{
get;
set;
}
private System.Timers.Timer JobProcessor;
public FtpFileSystemWatcher(string FtpLocationToWatch = "", string DownloadTo = "", int RecheckIntervalInSeconds = 1, string UserName = "", string Password = "", bool KeepOrignal = false, bool OverwriteExisting = false)
{
this.FtpUserName = UserName;
this.FtpPassword = Password;
this.FtpLocationToWatch = FtpLocationToWatch;
this.DownloadTo = DownloadTo;
this.KeepOrignal = KeepOrignal;
this.RecheckIntervalInSeconds = RecheckIntervalInSeconds;
this.OverwriteExisting = OverwriteExisting;
if (this.RecheckIntervalInSeconds < 1) this.RecheckIntervalInSeconds = 1;
}
public void StartDownloading()
{
JobProcessor = new Timer(this.RecheckIntervalInSeconds * 1000);
JobProcessor.AutoReset = false;
JobProcessor.Enabled = false;
JobProcessor.Elapsed += (sender, e) =>
{
try
{
this.IsRunning = true;
string[] FilesList = GetFilesList(this.FtpLocationToWatch, this.FtpUserName, this.FtpPassword);
if (FilesList == null || FilesList.Length < 1)
{
return;
}
foreach (string FileName in FilesList)
{
if (!string.IsNullOrWhiteSpace(FileName))
{
DownloadFile(this.FtpLocationToWatch, this.DownloadTo, FileName.Trim(), this.FtpUserName, this.FtpPassword, this.OverwriteExisting);
if (!this.KeepOrignal)
{
DeleteFile(Path.Combine(this.FtpLocationToWatch, FileName.Trim()), this.FtpUserName, this.FtpPassword);
}
}
}
this.IsRunning = false;
JobProcessor.Enabled = true;
}
catch (Exception exp)
{
this.IsRunning = false;
JobProcessor.Enabled = true;
Console.WriteLine(exp.Message);
}
};
JobProcessor.Start();
}
public void StopDownloading()
{
try
{
this.JobProcessor.Dispose();
this.IsRunning = false;
}
catch { }
}
private void DeleteFile(string FtpFilePath, string UserName, string Password)
{
FtpWebRequest FtpRequest;
FtpRequest = (FtpWebRequest)FtpWebRequest.Create(new Uri(FtpFilePath));
FtpRequest.UseBinary = true;
FtpRequest.Method = WebRequestMethods.Ftp.DeleteFile;
FtpRequest.Credentials = new NetworkCredential(UserName, Password);
FtpWebResponse response = (FtpWebResponse)FtpRequest.GetResponse();
response.Close();
}
private void DownloadFile(string FtpLocation, string FileSystemLocation, string FileName, string UserName, string Password, bool OverwriteExisting)
{
try
{
const int BufferSize = 2048;
byte[] Buffer = new byte[BufferSize];
FtpWebRequest Request;
FtpWebResponse Response;
if (File.Exists(Path.Combine(FileSystemLocation, FileName)))
{
if (OverwriteExisting)
{
File.Delete(Path.Combine(FileSystemLocation, FileName));
}
else
{
Console.WriteLine(string.Format("File {0} already exist.", FileName));
return;
}
}
Request = (FtpWebRequest)FtpWebRequest.Create(new Uri(Path.Combine(FtpLocation, FileName)));
Request.Credentials = new NetworkCredential(UserName, Password);
Request.Proxy = null;
Request.Method = WebRequestMethods.Ftp.DownloadFile;
Request.UseBinary = true;
Response = (FtpWebResponse)Request.GetResponse();
using (Stream s = Response.GetResponseStream())
{
using (FileStream fs = new FileStream(Path.Combine(FileSystemLocation, FileName), FileMode.CreateNew, FileAccess.ReadWrite))
{
while (s.Read(Buffer, 0, BufferSize) != -1)
{
fs.Write(Buffer, 0, BufferSize);
}
}
}
}
catch { }
}
private string[] GetFilesList(string FtpFolderPath, string UserName, string Password)
{
try
{
FtpWebRequest Request;
FtpWebResponse Response;
Request = (FtpWebRequest)FtpWebRequest.Create(new Uri(FtpFolderPath));
Request.Credentials = new NetworkCredential(UserName, Password);
Request.Proxy = null;
Request.Method = WebRequestMethods.Ftp.ListDirectory;
Request.UseBinary = true;
Response = (FtpWebResponse)Request.GetResponse();
StreamReader reader = new StreamReader(Response.GetResponseStream());
string Data = reader.ReadToEnd();
return Data.Split('\n');
}
catch
{
return null;
}
}
}
The way I handle this is to upload a one element byte array, named ".ftpComplete". The FileSystemWatcher only watches for ".ftpComplete" files, and strips that off the end to know the actual file uploaded. Since the".ftpComplete" file is only 1 byte, it uploads about as fast as it is created on the FTP server, so it can be deleted once you do whatever you need to with the main uploaded file
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(
FTPAddress + "/" + Path.GetFileName(filePath) + ".ftpComplete");
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false;
byte[] buffer = new byte[1];
Stream reqStream = request.GetRequestStream();
reqStream.Write(buffer, 0, buffer.Length);
reqStream.Close();
You could use a Robo-FTP script to monitor the FTP site for changes. Here is a link to a sample script that sends an email whenever a change is detected: http://kb.robo-ftp.com/script_library/show/40
I looked at the previous question that you linked. I think you should be able to modify the Robo-FTP sample and use the SETLEFT command with the /split option to make it parse the folder name and ISO file number of the changed file and then move the file to the proper location.
I'm building a windows service that grabs information from a website periodically
How can I start looking again when a exception is caught? for example when internet goes down and up later.
Code:
public string cadena(string pagina)
{
try
{
String cadena;
WebRequest myWebRequest = WebRequest.Create(pagina);
myWebrequest = 10000;
WebResponse myWebResponse = myWebRequest.GetResponse();
Stream ReceiveStream = myWebResponse.GetResponseStream();
Encoding encode = System.Text.Encoding.GetEncoding("ISO-8859-1");
StreamReader readStream = new StreamReader(ReceiveStream, encode);
cadena = readStream.ReadToEnd();
readStream.Close();
myWebResponse.Close();
return cadena;
}
catch (WebException error)
{
myTimer.Enabled = true;
return "error";
}
}
public void inicia(object sender, System.Timers.ElapsedEventArgs e)
{
myTimer.Enabled = false;
String strSite = cadena("www.something.com");
//Do something with strSite...
myTimer.Enabled = true;
}
protected override void OnStart(string[] args)
{
myTimer = new System.Timers.Timer();
myTimer.Interval = 1500;
myTimer.Elapsed += new System.Timers.ElapsedEventHandler(inicia);
myTimer.Enabled = true;
}
Here is a very crude example to get you started, this will keep your program from continuing until you get a valid response. There are better ways of doing this, but this is the idea you want. Good luck!
myWebResponse = myWebRequest.GetResponse();
while (myWebResponse.ContentLength == -1) {
//sleep
myWebResponse = myWebRequest.GetResponse();
}
//continue execution
You should probably put in a check to see if the remote site is available, and either poll until it is, or interrupt when the service is available. This way you won't have to recover from a thrown exception.
I think using exceptions should be reserved for things a little more catastrophic to your application.