I've been trying for a while now to set up an ftp connection with our mainframe via c#. So far I've been able to connect and upload a file to the mainframe, which is great, but the file has the wrong record length and is set up as variable, instead of fixed record length. After quite a bit a research I have come to the same conclusion as most people, that the ftpwebresponse function will not allow "qoute SITE" commands to be issued to the mainframe. If i'm wrong please don't hesitate to correct me, heres the code i'm using:
private void ftpButton_Click(object sender, EventArgs e)
{
string ftphost = "ftpSite";
string user = "myUser";
string pwd= "myPass";
string ftpfileName = "test.file2";
string inputfilePath="d:\\documents and settings\\gheff\\My Documents\\Visual Studio 2005\\Projects\\biWeeklyJob\\BiWeekly\\bin\\Debug\\file2.TXT";
string ftpfullpath = String.Format("ftp://{0}//'{1}'", ftphost,ftpfileName);
try
{
FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(ftpfullpath);
ftp.Credentials = new NetworkCredential(user,pwd);
ftp.KeepAlive = true;
ftp.UseBinary = false; //Use ascii.
ftp.Method = WebRequestMethods.Ftp.UploadFile;
FileStream fs = File.OpenRead(inputfilePath);
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
fs.Close();
Stream ftpstream = ftp.GetRequestStream();
ftpstream.Write(buffer, 0, buffer.Length);
ftpstream.Close();
}
catch (WebException ex)
{
String status = ((FtpWebResponse)ex.Response).StatusDescription;
throw new Exception(status);
}
}
So undeterred, I tried to think of another approach, I have successfully used the command line to upload a file, change the file properties and also changed the filetype so I can send JCL jobs to the mainframe. I am now tyring to implement this into my existing c# application, but proving harder than I thought.
I am by no means an expert in c#, but can use answers to then go and do more research to gain a better understanding.
I have seen this piece of code C# cmd excute commands, but looking around it seems that only one command can be issued from this.
So my question is, I know it took a while to get there, is it possible to run the follow commands on the command prompt without the use of a batch file as i'm looking some feedback as the process runs?
open "cmd.exe"
type "ftp"
type "FTPserver"
Type "USERNAME"
type "PASSWORD"
Then once connection has been established
then run pre-defined commands i.e upload files, upload and run JCL jobs.
I think what i'm looking for is somthing that will write text to cmd.exe but keep the session?
I hope this makes sense.
Any help would be greatly appreciated.
Thanks
So here is code you are asking for nevertheless I doubt that it solve your problem.
var cmd= new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.RedirectStandardInput = true;
cmd.Start();
using (var stdin = cmd.StandardInput)
{
stdin.WriteLine("ftp");
stdin.WriteLine("FTPserver");
stdin.WriteLine("USERNAME");
stdin.WriteLine("PASSWORD");
}
cmd.WaitForExit();
cmd.Close();
Try this cmd:
FTP -s:ftpcommandfilename url
sense the follow mode can run one command only, you can write the ftp cmd in a file and use this cmd to execute them.
WriteLine("FTP -s:ftpcommandfilename url");
By the way, I am also finding the multi-ftp-cmd-line-in-code mode, if you have got it, sharing?
I used this CodeProject project a few years ago for a simple application that needed to send some files. The thing that may help you is that it uses a socket to talk to the other server. You can send raw FTP commands which should sidestep the problems you're having with the FtpWebRequest object, without having to "shell out" and use the ftp command line program.
Another approach you could try is to submit a jcl job to allocate the dataset with the record length, block size, et al, that your process needs.
Once that job complets, "put" your data into the dataset you just allocated correctly. The z/OS ftp server should pick up the attributes from your existing dataset.
Have you considered using a commercial FTP client that supports a COM interface and is able to send raw protocol commands? This might not be economical if you are writing software to redistribute but if you are only trying to automate a recurring task for an internal IT project it could definately be worth it in terms of your time as a developer. Robo-FTP might be a good choice for connecting to a mainframe because it has built in ASCII to EBCDIC translation.
Related
So, the title may be misleading. I am building an android app that reads information from a text file, which is located on a cloud server (I would prefer to use either OneDrive, DropBox, or Google Drive [whichever is easiest]; others are fine). Periodically, the program will write information to the text file, still located on the cloud server. So, my question is twofold: Is it possible to read and write to a text file that is located on a cloud server? If so, how in the world would I complete this task? I have noticed the use of WebClient but I can't find a reasonable method or explanation on how this works. This program is coded in C#. This is what I have so far:
private string filename = "datafile.txt";
private List<Category> myList; //A list of an object that I developed ('Category')
//Allow the user interface to handle the error
public void readDatabase() {
//Here is where the magic has to occur, in order to read the file
...
//The usual reader that I use to read standard text files
StreamReader fileReader = new StreamReader(filename);
string line = "";
while ((line = fileReader.ReadLine()) != null)
//convertToCategory is my private method to convert the string to
myLine.Add(convertToCategory(line);
fileReader.close();
}
public void writeDatabase() {
//Here is where the magic has to occur, in order to write to the file
...
//The usual writer that I use to write standard text files
StreamWriter fileWriter = new StreamWriter(filename);
for (int i = 0; i < this.myList.Count; i++)
//toString() is something was developed in my object called 'Category'
fileWriter.WriteLine(fileWriter[i].toString());
fileWriter.close();
}
I would love to use Google Drive as my cloud server, but I am open to other possibilities, if necessary. I just want an easy and efficient method to read/write to the text file.
Possible Implementations:
Have seen possible solutions, where the file is downloaded locally and then read like normal and then uploaded at time of closing. However, if I could get away with it, I don't want the text file to be downloaded.
I have, also, seen several places where a SQL database is used in this instance. But the unfortunate thing is that I don't have any knowledge in developing with SQL. So, using a SQL server would be ideal (because speed is very important for this application) but it will be difficult for me to understand how it works.
A small question.. I have used sharpSSH to connect to SFTP server with "StrictHostKeyChecking" set to "yes". But, everytime I try to connect to a new SFTP server for the first time it asks me whether I want to trust a particular server finger print or not. Is there a way I can skip this step and accept it programmitically since I want minimal user interaction with this code? Also, I do not want to set "strictHostKeyChecking" to "no". Is there any workaround. I was thinking of adding the fingerprint in the Known_hosts file manually but I think I cannot do so as the finger prints are stored in encrypted format in known_hosts file. Can you please suggest some work-around for this?
My code goes as follows:
Tamir.SharpSsh.jsch.Session mySession = myJsch.getSession(_UserName,_ftpURL, _Port);
mySession.setPassword(_Password);
Hashtable config = new Hashtable();
config.Add("StrictHostKeyChecking", "yes");
mySession.setConfig(config);
byte[] fingerPrint_bytes = new byte[fingerPrint.Length * sizeof(char)];
System.Buffer.BlockCopy(fingerPrint.ToCharArray(), 0, fingerPrint_bytes, 0, fingerPrint_bytes.Length);
UserInfo ui=new MyUserInfo();
mySession.setUserInfo(ui);
myJsch.getHostKeyRepository().add(_ftpURL, fingerPrint_bytes, ui);
mySession.connect();
EDIT: Filezilla caused the problem, when i download files back from server it added new lines. I'm sorry for confusion.
This method upload files to ftp server and it's work fine, but in text files uploaded to server blank lines appear after every line("cr lf" appear), for example:
File:
First line
Second line
Third line
Uploaded file:
First line
Second line
Third line
Origin and uploaded files accordingly have different sizes, non-text files are the same.
Code:
private void sendFile(string In, string Out)
{
FtpWebRequest request = (FtpWebRequest) WebRequest.Create("ftp://domain//" + Out);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential("username", "password");
FileStream sourceStream = new FileStream(In, FileMode.Open, FileAccess.Read, FileShare.Read);
byte[] fileContents = new byte[sourceStream.Length];
sourceStream.Read(fileContents, 0, (int) sourceStream.Length);
sorceStream.Close();
request.ContentLength = fileContents.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
requestStream.Close();
}
How can i fix this?
EDIT: As the answer below doesn't seem to have helped (but I'm leaving it there for posterity as it shows better code) here are the next diagnostics steps I'd check:
How are you viewing the files? If at all possible, get onto the server directly rather than fetching the files again via a web browser or whatever.
What's the type of FTP server you're connecting to? Maybe there's a known issue.
Have you tried looking at what's actually being sent via Wireshark?
Have you tried sending the same files via a normal FTP client?
You should set FtpWebRequest.UseBinary to true in order to preserve the exact file contents. Otherwise the two systems will try to figure out line endings themselves, changing line terminators as they see fit. I very rarely think that's a good idea. (EDIT: UseBinary is actually true by default, but this sounds like the kind of problem introduced by using text mode... it certainly does no harm to make this explicit.)
Additionally:
You should be disposing of your FileStream via a using statement
You should be disposing of the request stream via a using statement
You should be taking note of the result of Stream.Read - it needn't always read the whole of the requested data in one go
You can either use File.ReadAllBytes to simply read the complete file data in one go, or use Stream.CopyTo (if you're using .NET 4) to copy the FileStream to the request stream (which won't set the content length, of course; I don't know whether this is a problem)
You're never calling GetResponse; it's unclear exactly what happens if you never fetch the response of an FtpWebRequest
Your parameter names don't match .NET naming conventions, and aren't very descriptive
So I would probably use:
private void SendFile(string inputFile, string outputPath)
{
FtpWebRequest request = (FtpWebRequest) WebRequest.Create
("ftp://domain//" + outputPath);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.UseBinary = true;
request.Credentials = new NetworkCredential("username", "password");
byte[] fileContents = File.ReadAllBytes(inputFile);
request.ContentLength = fileContents.Length;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(fileContents, 0, fileContents.Length);
}
// This *may* be necessary in order to validate that everything has happened
using (WebResponse response = request.GetResponse())
{
}
}
Its strange. I face the same problem and I was unable to fix it until I did not provide an extension in file. For Example if my file name was
abcfile
then I make it abcfile.dat and after that it shows me the uploaded file as actual file. I again upload file with abcfile.txt but this time again empty line problem appear in my uploaded file.
I suggest that you must provide extension to your file any except .txt.
The system that you're sending to uses different line endings to what your system uses. I can assume, because you get an extra line, that you're on Windows, and it uses CRLF endings. The system you're sending to recognises CR and LF as separate endings, so you get the extra lines.
For text, truncate the LF or the CR, see what happens. I have no clue about the differing file sizes.
In the top menu of FileZilla, set:
Transfer menu > Transfer type > binary
In the top menu of FileZilla, set:
Transfer menu > Transfer type > binary
It's working for me.
Been pulling my hair out over what should have been a quick and easy task.
I have a self-hosted WCF service in which I need to implement real-time video transcoding, the transcoding isn't a problem as such, using FFMpeg to a local temp file.
Quick sample of what my code looks like;
public Stream StreamMedia(int a)
{
String input = #"\media\" + a + ".mkv";
String output = #"\temp\transcoded\" + a + DateTime.Now.Ticks.ToString() + ".wmv";
ProcessStartInfo pi = new ProcessStartInfo("ffmpeg.exe");
pi.Arguments = "-i " + input + " -y -ab 64k -vcodec wmv2 -b 800k -mbd 2 -cmp 2 -subcmp 2 -s 320x180 -f asf " + output;
Process p = new Process;
p.StartInfo = pi;
p.Start();
Thread.Sleep(2500);
return new FileStream(output, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
}
The problem I am facing is that the returned Stream only gives me what was written to the file when it is returned - resulting in a rather short video file :)
I've played around with the obvious here, but no matter what I do it will only return what's available there and then.
What I need to happen is for the Stream to be returned with no respect to the actual current lenght of the output file - there is other code involved which makes sure the data is never sent to the client faster than what FFMpeg manages to encode, so basically I just need an open-ended stream.
Any takers?
One solution would be to create your custom Stream class which would wrap around the file from disk; BUT, there's also the concurrency issue, meaning that you need some locking mechanism as for the writing process (video transcoder) to properly share the file with your FileStream.
Is it possible for your transcoder to create multi-volume output? If so, then your lucky and this would work with (almost) no pain at all, just do the streaming of the volume N, then the transcoder writes the volume N + 1, and you'll not have any file access concurrency issues.
happy coding!
- Adrian
The simplest may be to use the Streaming Media service that is built into the operating system. See: http://technet.microsoft.com/en-us/windowsserver/dd448620
The other way to do it would be not to read from the file, but send the stream that is writing to the file, straight out to the client.
What is obvious is, this cannot be done via file system. You need a dynamic solution.
You can do it via your own made media service. In your case it could be a WCF or windows service.
This service should be responsible for both writing to the file (as data receives) and streaming.
I have to interface with a slightly archaic system that doesn't use webservices. In order to send data to this system, I need to post an XML document into a form on the other system's website. This XML document can get very large so I would like to compress it.
The other system sits on IIS and I use C# my end. I could of course implement something that compresses the data before posting it, but that requires the other system to change so it can decompress the data. I would like to avoid changing the other system as I don't own it.
I have heard vague things about enabling compression / http 1.1 in IIS and the browser but I have no idea how to translate that to my program. Basically, is there some property I can set in my program that will make my program automatically compress the data that it is sending to IIS and for IIS to seamlessly decompress it so the receiving app doesn't even know the difference?
Here is some sample code to show roughly what I am doing;
private static void demo()
{
Stream myRequestStream = null;
Stream myResponseStream = null;
HttpWebRequest myWebRequest = (HttpWebRequest)System.Net
.WebRequest.Create("http://example.com");
byte[] bytMessage = null;
bytMessage = Encoding.ASCII.GetBytes("data=xyz");
myWebRequest.ContentLength = bytMessage.Length;
myWebRequest.Method = "POST";
// Set the content type as form so that the data
// will be posted as form
myWebRequest.ContentType = "application/x-www-form-urlencoded";
//Get Stream object
myRequestStream = myWebRequest.GetRequestStream();
//Writes a sequence of bytes to the current stream
myRequestStream.Write(bytMessage, 0, bytMessage.Length);
//Close stream
myRequestStream.Close();
WebResponse myWebResponse = myWebRequest.GetResponse();
myResponseStream = myWebResponse.GetResponseStream();
}
"data=xyz" will actually be "data=[a several MB XML document]".
I am aware that this question may ultimately fall under the non-programming banner if this is achievable through non-programmatic means so apologies in advance.
I see no way to compress the data on one side and receiving them uncompressed on the other side without actively uncompressing the data..
No idea if this will work since all of the examples I could find were for download, but you could try using gzip to compress the data, then set the Content-Encoding header on the outgoing message to gzip. I believe that the Length should be the length of the zipped message, although you may want to play with making it the length of the unencoded message if that doesn't work.
Good luck.
EDIT I think the issue is whether the ISAPI filter that supports compression is ever/always/configurably invoked on upload. I couldn't find an answer to that so I suspect that the answer is never, but you won't know until you try (or find the answer that eluded me).