DonationCoder.com Forum

Main Area and Open Discussion => General Software Discussion => Topic started by: kyrathaba on May 13, 2011, 09:09 PM

Title: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 13, 2011, 09:09 PM
I have no problem doing this via Filezilla, but I need to figure out how to upload a file to my little corner of DC programmatically, from within my C# applications.  I've tried various things, from FTP classes I've both found and rolled myself, and using HttpWebRequest.  I also read about the winhttp.dll library, which some people say works whereas the internal C# stuff is not always robust (however, I have no experience with that library's functions).

The reason I need to be able to do this programmatically is that I've coded a game.  That game records the highscore, and updates that value whenever a player beats the previous high score.  I want the program to be able to upload the highscore.dat file (which contains not only the highscore, but also the name of the player who scored it) to a specific directory under http://kyrathaba.dcmembers.com

Does anyone have any working C# code that they've used successfully to upload a file to their DC webspace?  I know that DC uses explict FTP over TLS.  Perhaps the methods I've attempted aren't sophisticated enough to negotiate that.  At any rate, it'd be a real boon (not just to my current project, but also to future ones) if I could find a class or component that allows me this functionality.

I have used the code show here (http://kyrathaba.dcmembers.com/errata/ftp.htm) before successfully, on a non FTPES site, but can't get it to work here.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: Renegade on May 13, 2011, 09:27 PM
Have you looked at the Indy Project? I think there are C# bindings for it.

EDIT:

Yes -- here -- http://www.indyproject.org/SocketsCLR/index.EN.aspx

Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 13, 2011, 09:40 PM
Thanks for the possible help.  Looks like the project hasn't been updated since Feb. 2008, and that was has been done is mostly focused on SMTP/POP.  The only FTP related stuff I could find, so far, was:

Code: C# [Select]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace Indy.Sockets.Web {
  7.     class FTP {
  8.     }
  9. }

I'll keep looking through the download and documentation, though, just to be thorough.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 13, 2011, 09:54 PM
I tried the following code in a console program, and received this error message:
The remote server returned an error: (530) Not logged in.

Code: C# [Select]
  1. static void Main(string[] args) {
  2.  
  3.             // Get the object used to communicate with the server.
  4.             FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://kyrathaba.dcmembers.com/testbed/test.txt");
  5.             request.Method = WebRequestMethods.Ftp.UploadFile;
  6.  
  7.             request.Credentials = new NetworkCredential("kyrathaba", "substitutedForActualPasswordInThisForumPost");
  8.  
  9.             // Copy the contents of the file to the request stream.
  10.             StreamReader sourceStream = new StreamReader("test.txt");
  11.             byte[] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
  12.             sourceStream.Close();
  13.             request.ContentLength = fileContents.Length;
  14.  
  15.             Stream requestStream = request.GetRequestStream();
  16.             requestStream.Write(fileContents, 0, fileContents.Length);
  17.             requestStream.Close();
  18.  
  19.             FtpWebResponse response = (FtpWebResponse)request.GetResponse();
  20.  
  21.             Console.WriteLine("Upload File Complete, status {0}", response.StatusDescription);
  22.  
  23.             response.Close();
  24.  
  25.             Console.WriteLine("Press a key to end program...");
  26.             Console.ReadKey();
  27.         }
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: hamradio on May 13, 2011, 10:50 PM
Only concern I got is how are you going to keep people from using a .net disassembler to see the password?
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: mouser on May 13, 2011, 11:46 PM
To follow up on ham's point -- you'd be insane to try to save high scores by embedding ftp login credentials in your public app and using ftp protocol to upload user high scores.  That's just not the way it's done.

If you want to save high scores the solution is to write a server based script (php, python, perl, dot net on the server, whatever), that responds to http queries from client application over the web, like any other web-based application, and updates the server database, etc.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 07:44 AM
I don't know how to write server-side scripts.  I guess I could just put up a submission form on a webpage and then have the program direct the user to that form to submit a file via by posting.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 07:45 AM
Or, the program could invoke the user's default email client to have them send their obfuscated highscore file to me.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 07:47 AM
Only concern I got is how are you going to keep people from using a .net disassembler to see the password?

To follow up on ham's point -- you'd be insane to try to save high scores by embedding ftp login credentials in your public app

Sorry guys, didn't realize.  That's one thing I value most highly about DC; gaining the benefit of others' expertise.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: wraith808 on May 14, 2011, 09:40 AM
You could also use encryption, and get it from a file if you want to use FTP.

Code: C# [Select]
  1. using System;
  2. using System.Security.Cryptography;
  3. using System.Text;
  4.  
  5. namespace Coderz808
  6. {
  7.     public static class EnDeCrypter
  8.     {
  9.         // Set this to some personalized crypto key
  10.         private const string cryptoKey = "someSortOfCryptoKey";
  11.  
  12.         // The Initialization Vector for the DES encryption routine (choose 8 personalized bytes)
  13.         private static readonly byte[] IV =
  14.             new byte[8] { 140, 103, 145, 2, 10, 176, 173, 9 };
  15.  
  16.         /// <summary>
  17.         /// Encrypts provided string parameter
  18.         /// </summary>
  19.         internal static string Encrypt(string s)
  20.         {
  21.             if (s == null || s.Length == 0) return string.Empty;
  22.  
  23.             string result = string.Empty;
  24.  
  25.             try
  26.             {
  27.                 byte[] buffer = Encoding.ASCII.GetBytes(s);
  28.  
  29.                 TripleDESCryptoServiceProvider des =
  30.                     new TripleDESCryptoServiceProvider();
  31.  
  32.                 MD5CryptoServiceProvider MD5 =
  33.                     new MD5CryptoServiceProvider();
  34.  
  35.                 des.Key =
  36.                     MD5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(cryptoKey));
  37.  
  38.                 des.IV = IV;
  39.                 result = Convert.ToBase64String(
  40.                     des.CreateEncryptor().TransformFinalBlock(
  41.                         buffer, 0, buffer.Length));
  42.             }
  43.             catch
  44.             {
  45.                 throw;
  46.             }
  47.  
  48.             return result;
  49.         }
  50.  
  51.         /// <summary>
  52.         /// Decrypts provided string parameter
  53.         /// </summary>
  54.         internal static string Decrypt(string s)
  55.         {
  56.             if (s == null || s.Length == 0) return string.Empty;
  57.  
  58.             string result = string.Empty;
  59.  
  60.             try
  61.             {
  62.                 byte[] buffer = Convert.FromBase64String(s);
  63.  
  64.                 TripleDESCryptoServiceProvider des =
  65.                     new TripleDESCryptoServiceProvider();
  66.  
  67.                 MD5CryptoServiceProvider MD5 =
  68.                     new MD5CryptoServiceProvider();
  69.  
  70.                 des.Key =
  71.                     MD5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(cryptoKey));
  72.  
  73.                 des.IV = IV;
  74.  
  75.                 result = Encoding.ASCII.GetString(
  76.                     des.CreateDecryptor().TransformFinalBlock(
  77.                     buffer, 0, buffer.Length));
  78.             }
  79.             catch
  80.             {
  81.                 throw;
  82.             }
  83.  
  84.             return result;
  85.         }
  86.     }    
  87. }
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 09:42 AM
Thanks, wraith.  Yes, and I have the know-how to encrypt a password in my app.  I wouldn't put it in raw.  But I understand that it's better, probably to use some other file-submission method.

Let me ask this: does DC have a server-side script I could reference from the html code in a webpage, so that a user could upload a small (few bytes) binary file to a designated /incoming/ directory of my webspace?
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: worstje on May 14, 2011, 10:16 AM
I have an ugly C# function I cobbled together for JottiQ that supports both GET and POST methods, the latter of which supports filetransfers. The code is butt ugly, but it is functional. It returns a XMLDocument if I recall properly, but could be simplified to just return a stream I believe.

Let me know if it would be good enough for your needs, and I'll supply you after my shopping run has provided me with foodstuffs to last the weekend. It's probably an excellent example of how not to deal with webservices in .NET, but I don't care much. :)
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: Renegade on May 14, 2011, 10:36 AM
I have an ugly C# function I cobbled together... It's probably an excellent example of how not to deal with webservices in .NET, but I don't care much. :)

Hip! Hip! Horray~!

Let's hear it for getting things done~! :)

I have so much code that's ugly, but works... I wouldn't show it to anyone.

Sure, I could clean it up and make it pretty and all that, but... Time...

+1 for getting things done. :)
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: worstje on May 14, 2011, 10:52 AM
Good point. I hereby rescind my offer to share my code. :-[ The internet has far too long a memory for me to want to carry that blemish for the rest of my life. :mad:

Just kidding, I don't give a damn. Just let me know. 8)

Edit: On second thought, I re-read his request, and I think I've got the opposite. I have got client-side C# code that can upload to some http:// script, while I now think he wants a server-side script to receive file uploads and store them with. And with that, I am afraid I cannot help.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: mouser on May 14, 2011, 11:36 AM
I don't know how to write server-side scripts.

kyrathaba, you're a fast learner and, while i'm not suggesting you learn how to write server scripts for this project, i would suggest that you might find it very enjoyable to learn a little bit of php, just as a change of pace from desktop application coding.  it would also give you a feel for what kinds of things you can do with server side coding.

why not get yourself a book and start the php programming school assignments here (https://www.donationcoder.com/forum/index.php?board=80.0).
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 12:41 PM
Mouser, I promise to look into PHP.  In the meantime, worstje, I'd be very grateful for your ugly code ;)  I promise never to share/re-post it anywhere. 
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 12:45 PM
Here (http://kyrathaba.dcmembers.com/my_programs/KyrHangmanSetups/KyrHangman1010Setup.zip)'s my application in its current incarnation (screenshot (http://kyrathaba.dcmembers.com/my_programs/program_screenshots/hangman.png)).  I want to add a menu item "Share my highscore", or something to that effect.  It should allow the user to upload the small (20-50 byte) file containing their highscore to a designated /incoming/ directory on DC.  I would have another utility program that allows me to scan that particular online folder and download all such files currently residing their, opening each, retrieving username and highscore, and compiling an HTML file showing a listing of the game's users and their highscores in descending order.

Would something like this (modified slightly) work?  I realize there has be a complimentary PHP script residing on the server...

<form enctype="multipart/form-data" action="uploader.php" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="100000" />
Choose a file to upload: <input name="uploadedfile" type="file" /><br />
<input type="submit" value="Upload File" />
</form>

[ You are not allowed to view attachments ]
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: mouser on May 14, 2011, 01:59 PM
It should allow the user to upload the small (20-50 byte) file containing their highscore to a designated /incoming/ directory on DC.  I would have another utility program that allows me to scan that particular online folder and download all such files currently residing their, opening each, retrieving username and highscore, and compiling an HTML file showing a listing of the game's users and their highscores in descending order.

:)

think about what you are saying.

You want client to be able to "upload a 20-50 byte FILE" and then you want them to be able to view other people's high scores by scanning a server folder, downloading all other highscore files, opening each, reading info, and then "compiling an HTML file" on the local pc and displaying it.

You need to shift your thinking.

You do not want this.

What you want is something 1000x simpler and more straightforward.

You want a server script that will accept two very simple http requests, the first will be submission of high score info, it could be as simple as accepting an http request of http:/kyrathaba.com/highscoresubmit?name=mouser&score=54  or you could use a post form method.

The server script will then simply ADD the users score to its high score database.

And then to VIEW high scores from the desktop application, you will simply make another web query to the server script of the form http://kyrathaba.com/highscores.php which will RETURN AN HTML FILE that the client can display to view high scores.  Users could even just view that web page directly.  (Or alternatively return a response with some raw data from the database for you to format and display).

You need to stop thinking about doing this purely from the desktop application using protocols like ftp.  That way lies madness.



You need to wrap your head around web coding so that you have a better taste for what things you should be doing server-side vs. desktop client side.  Go read a few pages about web coding (php, perl, whatever) and using database stuff on the server, etc.  You will find it is both easy, fun, and liberating.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 02:05 PM
Yeah, I'm very desktopApp-centric in my thinking, because that's all I've every done.  It would be better if the server did it all.  Is there some sort of free desktop app that I could use in conjunction with developing such a script, just to test the script and know that it will work once uploaded to a server?  Or can I just tinker with scripts, uploading them to one of my subdirectories and testing them directly?
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: worstje on May 14, 2011, 02:10 PM
You can install a local webserver to develop on, or you can upload each time. For as far software goes, usually a simple webbrowser will do miracles (with or without a temporary html page that has a form that allows you to create the proper sort of request).

Either way, I am fully in agreement with mouser. You'll want some scripts on the webserver. Nothing more, nothing less. Forget all that crap about uploading files, scanning directories, etc etc. :)
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: mouser on May 14, 2011, 02:11 PM
Yeah, I'm very desktopApp-centric in my thinking, because that's all I've every done.  It would be better if the server did it all.  Is there some sort of free desktop app that I could use in conjunction with developing such a script, just to test the script and know that it will work once uploaded to a server?

What you should do is install a "LAMP (http://en.wikipedia.org/wiki/LAMP_%28software_bundle%29)" bundle on your local pc, and which will let you do and test all your web development initially on your desktop.

I don't know which package people currently recommend for windows, but one is XAMPP: http://www.apachefriends.org/en/xampp-windows.html  which is probably a good option.

The most confusing part is actually getting setup and just getting started.  After that you will probably find web coding highly rewarding and invigorating.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: mouser on May 14, 2011, 02:15 PM
Run don't walk to your nearest bookstore or online retailer and buy yourself a book on PHP/MYSQL.  One i like is http://www.amazon.com/PHP-MySQL-Web-Development-4th/dp/0672329166/ but any one that grabs your attention will do.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 02:18 PM
Okay, I'm convinced. 

Unfortunately, this is going to mean delaying releasing this app.  What I really want to do is spend some time in the next few weeks working through the Stage 2 (https://www.donationcoder.com/forum/index.php?board=181.0) C# assignments in the Programming School.  But now it looks like I'll have to break away long enough to figure out how to do the PHP I need for Highscores submission, collating, and reporting in a webpage.

Shouldn't be that hard, once I understand the syntax of PHP.  Basically, each 'highscore.dat' file just contains a single line of text, such as these three examples, and the program splits them into 'highscore' and 'userWhoAchievedThisHighscore' using the semicolon character as a delimeter:

10500;mouser
8755;kyrathaba
12200;worstje

When it saves a 'highscore' on disk, it encrypts it first, so the user(s) of the game can't peek.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 02:24 PM
So, how would this work, mouser?  I have to get some PHP working on XAMP, then submit it to you for proofing/approval, and then it goes in some special directory on the DC server?  Or can the script run within a subidrectory of my own DC webspace?
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: mouser on May 14, 2011, 02:27 PM
Or can the script run within a subidrectory of my own DC webspace?

You can just upload the php files and access and test them from the web, no special permissions or work needed behind the scenes for php.  you are going to be pleasantly surprised at how easy it is to start writing server scripts that do interesting things.

The only thing you WILL have to eventually have us do is create the initial database for you on the server.  after that you will be able to access it and modify it from your scripts.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 02:31 PM
This database would hold the submitted files?
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: mouser on May 14, 2011, 02:32 PM
you wont be storing submitted files.  you will be storing HIGH SCORE DATA in a database.  And your desktop app won't be submitting FILES it will be submitting a simple http request with the users score submission data.

it's really much simpler than you are thinking, and it will all start to make sense as you learn about it.  but you'll need to stop thinking in terms of files moving around.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 02:37 PM
Ah, I get it!  Yeah, I've been making it way harder than it is.  I keep thinking in terms of files because

(a) you'd send me a "file" via email
(b) my desktop apps deal with "files"

But all the webpage script needs is the data that's in the files.  Sweet.

So the database you'd eventually create would only be for my game's highscore data, right?  And later, if I had another project that needed such web-reciprocity, it'd use a different database (understanding, of course, that it might be possible that some apps could share certain databases, depending on circumstances).
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: mouser on May 14, 2011, 03:17 PM
Databases hold "tables" which are like the tables in a spreadsheet, with columns (fields) and rows.

So you can actually put lots of different tables for different projects in the same single database.

But in general people tend to use separate databases for different large projects.  So a wordpress blog, or this forum, uses one database to store all of its many tables, and that database does not contain tables for other projects.

For small experimental projects, you would probably use one database for all of them, using different tables for your different experiments.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 03:31 PM
Do I want to install the three services shown in this setup screen?  Or will each be activated 'as needed' if I don't make them services?  In short, I don't mind installing them as services if they'll avoid headaches as I learn PHP.  But, if the differences would be transparent to me, I'd just soon not install them as services.

[ You are not allowed to view attachments ]

Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: worstje on May 14, 2011, 03:42 PM
For PHP, you only need Apache to run a webserver.
MySQL is the most popular database which you'll probably need if you want to do more complicated stuff. (Although if you've got other databases available already, you can use those instead and won't need MySQL.)
Filezilla is a ftp server.

Since you only want to use the http protocol, you only need the first for a php development environment.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: mouser on May 14, 2011, 04:03 PM
you are going to need mysql (as well as php) for your development coding, but whether it has to be installed as a service is a different matter.

i'd say for getting started, just install both php and mysql as services.  then you can undo that later if you wish.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: Deozaan on May 14, 2011, 04:16 PM
FYI for a "Portable" version of XAMPP: (http://portableapps.com/apps/development/xampp)

XAMPP isn't in PortableApps.com Format, but it easily integrates with the PortableApps.com Suite by using the XAMPP Launcher 1.4 and installing XAMPP in the root directory of your portable device (as recommended).
-http://portableapps.com/apps/development/xampp
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 05:08 PM
Thanks, folks!  Installing ............. 63% ......
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 05:40 PM
Look okay for what I'll need, just to begin learning and to complete the PHP lessons in Programming School?

[ You are not allowed to view attachments ]
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: mouser on May 14, 2011, 06:03 PM
yep.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 06:12 PM
Thanks.




My first PHP program:

[ You are not allowed to view attachments ]
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: mouser on May 14, 2011, 06:33 PM
having fun yet?
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 06:38 PM
Yeah, actually! :)

I'm coding a PHP-driven address book that'll use a webpage interfaced with a database to pull data from and push data to the pertinent table in a database...
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 08:05 PM
Okay, through experimentation and browsing some of the documentation, I've been able to:

(a) create a database containing a single table, using phpMyAdmin
(b) created a single table
(c) populated that table with five rows, consisting of three fields each: ID, DC username, and DC user's website URL

Then, I wrote a PHP/XHTML file to pull data from the database and display it.

The result is shown here, and I've attached the MySql database and my PHP code as a zip.  Am I on the right track?

[ You are not allowed to view attachments ]

I've I'm not mistaken, this example is not much less complex than what I want to do with my game's highscores.  At least, as far as processing data within the while( ) loop in the PHP code.  Reckon I'd just need a bit more code in order to allow a user to submit data from my desktopApp game...
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 14, 2011, 10:13 PM
Awesomeness... :)

I've gotten the following example working.  I'm able to use the form's post method to add new data to the database and then refresh the webpage to update the html table with the added data (I added Renegade and hamradio's data solely using the web-form's post action):

[ You are not allowed to view attachments ]

Project files developed using XAMPP are attached.

Fantastic!

Mouser, don't you think that what I'm wanting to do with 'highScore' data from the game I'm developing falls along the lines of what this example accomplishes?  Basically, I could have my game app programmatically use such a form post-action to send its data to an online database, right?

For instance, couldn't I replace...

$_POST['MyUsrName'];

with...

$_POST[183];

or

$_POST["Ben Franklin"];

as long as in place of the variable I'm using the type of value the database is expecting (int, string, etc)?
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: Deozaan on May 15, 2011, 01:16 AM
Mouser, don't you think that what I'm wanting to do with 'highScore' data from the game I'm developing falls along the lines of what this example accomplishes?  Basically, I could have my game app programmatically use such a form post-action to send its data to an online database, right?

I know that was directed at mouser, but yeah, I do think that's basically what you want.

But you probably also want some sort of verification that it's coming from the game or that the score is legitimate so people don't just type in their own $_POST[189135105313546843]; to give themselves a cheater high score.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 15, 2011, 08:10 AM
Excellent point, Deozaan, and easy to do.  Thanks.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 15, 2011, 09:22 AM
Let's say I have a C# desktop WinForms application that wants to submit a 'DC_username' and 'User_website' just like the php code does in my above example.  How can the C# app silently (in other words, without requiring the user to type in these values on a form) send these to my update.php page so that it is indistinguishable from the form submit, as far as the php is concerned?

For example, I put the following code in a button's click event, in a C# test program.  It adds a row to the HTML table on my .../addressBook.php page, but both fields are blank:

           string URI = "http://localhost/addressBook/update.php";

            WebClient wc = new WebClient();
            NameValueCollection NC = new NameValueCollection();
            NC.Add("sampleUserName","sampleWebsiteURL");
            byte[] response = wc.UploadValues(URI,NC);
            string responseString = Encoding.ASCII.GetString(response);
            MessageBox.Show(responseString);

[ You are not allowed to view attachments ]

The update.php page is expecting to receive POST data like this:

$Usr = $_POST['MyUsrName'];
$UsrUrl = $_POST['MyUsrWebsite'];

Is there some way I need to change the format of the data I'm passing into NC above?  Obviously, my update.php page is receiving something, or it wouldn't update the HTML table with blank values.  I need need to figure out how to make my C# app send data in a way that the php recognizes it as the two post variables shown above, right?
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: worstje on May 15, 2011, 09:49 AM
Give me a few minutes to edit my JottiQ code to remove some passwords and other stuff you don't need, and you'll have a sample. :)
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 15, 2011, 09:52 AM
Give me a few minutes to edit my JottiQ code to remove some passwords and other stuff you don't need, and you'll have a sample. smiley

Wonderful.  I'll check back in a couple hours.  Thanks!
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: worstje on May 15, 2011, 10:16 AM
Here, code plus example-ish. You'll want to gut the stuff further.

XmlHelper.cs, gutted a fair amount and an excellent example of ugly code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Net;
using System.Xml;
using System.IO;

using System.Reflection;
using System.ComponentModel;
using System.Threading;

namespace JottiQ
{
    public enum HttpMethod
    {
        Get,
        Post,
    }

    public class UserCanceledException : Exception
    {
        public UserCanceledException()
            : base()
        {
        }

        public UserCanceledException(string message)
            : base(message)
        {
        }

        public UserCanceledException(string message, Exception inner)
            : base(message, inner)
        {
        }
    }

    class XmlHelper
    {
        static private NetworkCredential ApiCredentials = new NetworkCredential("Wouldn't_You", "Like_To_Know");
        static private string userAgent = null;

        public static string UserAgent
        {
            get
            {
                if (userAgent == null)
                {
                    System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
                    System.Reflection.AssemblyName name = assembly.GetName();
                    System.Version version = name.Version;

                    userAgent = name.Name + " v" + version.ToString();
                }

                return userAgent;
            }
        }

        public class FileUploadData : INotifyPropertyChanged, Status.IProgressStatusReporter
        {
            public event PropertyChangedEventHandler PropertyChanged;

            public delegate bool CanContinueDelegate();

            private string filename;
            private Stream stream;
            private JottiItem ji;   /* TODO: Temporary. Please fix! */
            private CanContinueDelegate ccd;

            public string FileName
            {
                get { return this.filename; }
            }

            public Stream Stream
            {
                get { return this.stream; }
            }

            public JottiItem JI
            {
                get { return ji; }
            }

            public CanContinueDelegate CanContinue
            {
                get { return ccd; }
            }

            public FileUploadData(string filename, Stream stream, JottiItem ji, CanContinueDelegate canContinue)
            {
                this.filename = filename;
                this.stream = stream;
                this.ji = ji;
                this.ccd = canContinue;
            }

            protected void OnPropertyChanged(string name)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(name));
                }
            }

            /* IProgressStatusReporter implementation */
            public long Min
            {
                get
                {
                    return 0;
                }
            }

            public long Max
            {
                get
                {
                    return (this.stream != null) ? this.stream.Length : 0;
                }
            }

            public long Progress
            {
                get
                {
                    return (this.stream != null) ? this.stream.Position : 0;//(this.stream.Position*10)/this.stream.Length : 0;
                }
            }

            public void Update()
            {
                OnPropertyChanged("Progress");
            }
        }

        static public XmlDocument getXmlResponse(string inURL, HttpMethod hm, Dictionary<string, object> fields)
        {
            /* HTTPWebRequest, XMLDocument */
            HttpWebRequest myHttpWebRequest;
            HttpWebResponse myHttpWebResponse;
            XmlDocument myXMLDocument;
            XmlTextReader myXMLReader;

            try
            {
                if ((hm == HttpMethod.Get) && (fields != null))
                {
                    StringBuilder sb = new StringBuilder();
                    sb.Append(inURL);
                    sb.Append("?");

                    foreach (KeyValuePair<string, object> pair in fields)
                    {
                        sb.Append(pair.Key);
                        sb.Append("=");
                        sb.Append(pair.Value);
                        sb.Append("&");

                    }

                    inURL = sb.ToString();
                }

                //Create Request
                myHttpWebRequest = (HttpWebRequest)HttpWebRequest.Create(inURL);
                myHttpWebRequest.Credentials = ApiCredentials;
                myHttpWebRequest.PreAuthenticate = true;
                myHttpWebRequest.UserAgent = UserAgent;

                if (hm == HttpMethod.Get)
                {
                    myHttpWebRequest.Method = "GET";
                    myHttpWebRequest.ContentType = "application/x-www-form-urlencoded; encoding='utf-8'"; //"text/xml; encoding='utf-8'";
                }
                else if (fields == null)
                {
                    /* If there's no parameters to send, we don't need to be difficult either. */
                    myHttpWebRequest.Method = "POST";
                }
                else
                {
                    myHttpWebRequest.Method = "POST";
                    // The value "multipart/form-data" should be used in combination with the INPUT element, type="file".

                    /* When we're uploading a good chunk of data, there is a huge chance of a
                     * KeepAlive bug crashing us halfway through. Disable those. */
                    myHttpWebRequest.KeepAlive = false;
                    myHttpWebRequest.Timeout = 6 * 60 * 60 * 1000;   // 6 hours should be enough for everyone.

                    /* Since we are using multipart/form-data, we need to be difficult with boundaries. */
                    string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
                    myHttpWebRequest.ContentType = "multipart/form-data; boundary=" + boundary;

                    // Get the boundary in bytes
                    byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

                    // 1. Calculate total length of entire message (by fake-building it)
                    // 2. Send content-length.
                    // 3. Send actual multipart stuff. This avoids having a huge file upload in memory.

                    // --BOUNDARY
                    // Content-Disposition: form-data; name="<NAME>"
                    //
                    // sadfasdfasdf
                    // --BOUNDARY
                    // Content-Disposition: form-data; name="<NAME>"; filename="C:\file1.txt"
                    // Content-Type: application/octet-stream
                    // --BOUNDARY--

                    long contentLength = 0;
                    string fileTemplate = "Content-Disposition: form-data; name=\"{0}\";filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n";
                    string miscTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n";

                    foreach (KeyValuePair<string, object> pair in fields)
                    {
                        if (pair.Value is FileUploadData)
                        {
                            FileUploadData fud = (FileUploadData)pair.Value;
                            string fileHeader = string.Format(fileTemplate, pair.Key, fud.FileName);

                            //convert the header to a byte array
                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(fileHeader);

                            contentLength += boundarybytes.Length + bytes.Length + fud.Stream.Length;
                        }
                        else
                        {
                            string miscHeader = string.Format(miscTemplate, pair.Key);
                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(miscHeader);
                            contentLength += boundarybytes.Length + bytes.Length + pair.Value.ToString().Length;
                        }
                    }

                    contentLength += boundarybytes.Length + 2;   /* extra 2 -- at the end of final boundary */
                    myHttpWebRequest.ContentLength = contentLength;

                    /* Step 3. Send the actual data and stuff. */
                    Stream requestStream = myHttpWebRequest.GetRequestStream();
                    
                    foreach (KeyValuePair<string, object> pair in fields)
                    {
                        requestStream.Write(boundarybytes, 0, boundarybytes.Length);
                        
                        if (pair.Value is FileUploadData)
                        {
                            FileUploadData fud = (FileUploadData)pair.Value;
                            string fileHeader = string.Format(fileTemplate, pair.Key, fud.FileName);
                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(fileHeader);
                            requestStream.Write(bytes, 0, bytes.Length);

                            // Use 4096*2 for the buffer / make that *4 to streamline IO over UI updates
                            byte[] buffer = new byte[4096*4];

                            int bytesRead = 0;
                            int bytesTotal = 0;
                            // Loop through whole file uploading parts in a stream.
                            while ((bytesRead = fud.Stream.Read(buffer, 0, buffer.Length)) != 0)
                            {
                                requestStream.Write(buffer, 0, bytesRead);
                                requestStream.Flush();

                                /* Temporary solution for live updates. */
                                bytesTotal += bytesRead;
                                fud.JI.StatusMessage = "Upload " + ((bytesTotal * 100) / fud.Stream.Length).ToString() + "% complete.";

                                fud.Update();
                                if (!fud.CanContinue())
                                    throw new UserCanceledException("Upload has been canceled by user.");
                            }
                            fud.JI.StatusMessage = "Upload done.";
                        }
                        else
                        {
                            string miscHeader = string.Format(miscTemplate, pair.Key);
                            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(miscHeader);
                            requestStream.Write(bytes, 0, bytes.Length);

                            bytes = System.Text.Encoding.UTF8.GetBytes(pair.Value.ToString());
                            requestStream.Write(bytes, 0, bytes.Length);
                        }
                    }

                    // Write out the final boundary
                    boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
                    requestStream.Write(boundarybytes, 0, boundarybytes.Length);

                    // Close our stream.
                    requestStream.Close();
                }

                //Get Response
                myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();

                //Now load the XML Document
                myXMLDocument = new XmlDocument();

                //Load response stream into XMLReader
                myXMLReader = new XmlTextReader(myHttpWebResponse.GetResponseStream());
                myXMLDocument.Load(myXMLReader);
            }
            catch (Exception myException)
            {
                throw new Exception("Error Occurred in getXMLResponse()", myException);
                //return null;
            }
            finally
            {
                myHttpWebRequest = null;
                myHttpWebResponse = null;
                myXMLReader = null;
            }

            return myXMLDocument;
        }

    }
}

It works to the extent I need it to, which admittedly isn't much at all. :) You'll want the getXmlResponse() method, which I originally took from some online example and heavily adjusted to suit my own needs. For JottiQ fileuploads, I call it like this (in a seperate thread):

XmlHelper.FileUploadData fud = new XmlHelper.FileUploadData(
                            System.IO.Path.GetFileName(ji.FilePath),
                            fileStream, ji,
                            delegate() { return !_terminated; });
//getXmlResponseWrapper() wraps various error-handling stuffs.
XmlDocument xml = getXmlResponseWrapper(ji, true, inURL, HttpMethod.Post,
                new Dictionary<string, object>()
                    {
                        {"token", token},
                        {"scanfile", fud}
                    }
                    );

The entire passing of ji to the function or its upload components is a bit of a hack I used for updating the display while uploading; I am actually in the process of taking that out which is why the code is very bi-polar in nature right now. The delegate serves the purpose of making the upload process cancelable.

In the above example, the token is a string. scanfile acts like like one of those file upload controls. I ended up reinventing the wheel of implementing the POST protocol because I couldn't find any builtin libraries that actually did that already. (Also, file upload things only work for POST method since the data is too much to fit in a GET request.) In your example, you can probably suffice with a single call like:

XmlDocument xml = getXmlResponse(inURL, HttpMethod.Post,
                new Dictionary<string, object>()
                    {
                        {"user", getUsernameString()},
                        {"uid", getUniqueID()}
                    }
                    );

...and so forth. The code doesn't do much error-checking, or URL encoding of parameter names (& -> %26 or + -> %2B) and the sort since my needs were simple and very well-defined so that I knew I would not need to worry about those cases. That may not be the case for you however. Hell, you may not even want to implement your script to return XML data, so then you could gut the XML loading bit out too.

Code highlighting removed since the highlighter turns all the indenting into &#160; repetitions. I'll gladly put it back in when mouser fixes the highlighter.
Title: Re: functional C# class/component to upload to my DC space via explicit FTP over TLS
Post by: kyrathaba on May 15, 2011, 12:14 PM
Thanks very much.  I'll see what I can do with this! :)