BackgroundWorker ReportProgress from Different Class - c#

I'm going in circles searching and reading forums on how to solve this problems. After a day of trying I'm still at a loss how to solve my problem. I'm uploading a file and need to return the % in a a textbox. I'm having no problem with the upload portion and have no problems returning the values using the BackgroundWorker if I include all my code within the same class. However, what I'm doing is calling an ftp class from form1. I need the ftp class to return the percentage to form1 so I can can display in my UI and also need to have the server response codes returned from my ftp class to display in my form1. Everything was working ok before I tried to run this in a BackgroundWorker process, with the exception of course that the UI becomes unresponsive and returns all status messages after upload completed. Heres my code as it stands now. How do I get the percentage from ftp class and pass it back to form1, as well as the server response code once completed?
public partial class Form1 : Form
{
private BackgroundWorker bw = new BackgroundWorker();
private string ftpServer = #"ftp://10.0.0.0";
private string ftpUser = #"user";
private string ftpPass = #"pass";
private string ftpRemoteFile = #"myfile.exe";
private string ftpLocalFile = #"C:\Uploads\file.exe";
public Form1()
{
InitializeComponent();
bw.WorkerReportsProgress = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
private void sendButton_Click(object sender, EventArgs e)
{
progressRichTextBox.Text = "Sending";
if (bw.IsBusy != true)
{
bw.RunWorkerAsync();
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
ftp ftpClient = new ftp(ftpServer, ftpUser, ftpPass);
ftpClient.upload(progressRichTextBox, ftpRemoteFile, ftpLocalFile);
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (!(e.Error == null))
{
this.progressRichTextBox.Text = ("Error: " + e.Error.Message);
}
else
{
this.progressRichTextBox.Text = "Done!";
}
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.progressRichTextBox.Text = (e.ProgressPercentage.ToString() + "%");
}
}
And heres the ftp class:
public void upload(System.Windows.Forms.RichTextBox progressRichTextBox, string remoteFile, string localFile)
{
FileInfo fileInfo = new FileInfo(localFile);
/* Create an FTP Request */
ftpRequest = (FtpWebRequest)FtpWebRequest.Create(host + "/" + remoteFile);
/* Log in to the FTP Server with the User Name and Password Provided */
ftpRequest.Credentials = new NetworkCredential(user, pass);
/* Specify generic group name for faster upload */
ftpRequest.ConnectionGroupName = "AffiliateUpload";
/* Specify the Type of FTP Request */
ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
/* Server connection options */
ftpRequest.UseBinary = true;
ftpRequest.UsePassive = true;
ftpRequest.KeepAlive = true;
ftpRequest.ContentLength = fileInfo.Length;
/* Buffer for the Data */
byte[] buff = new byte[bufferSize];
int contentLen;
/* Open a File Stream to Read the File for Upload */
FileStream localFileStream = fileInfo.OpenRead();
try
{
// Stream to which the file to be upload is written
ftpStream = ftpRequest.GetRequestStream();
// Read from the file stream 2kb at a time
contentLen = localFileStream.Read(buff, 0, bufferSize);
// Till Stream content ends
while (contentLen != 0)
{
// Write Content from the file stream to the
// FTP Upload Stream
ftpStream.Write(buff, 0, contentLen);
contentLen = localFileStream.Read(buff, 0, bufferSize);
}
// Close the file stream and the Request Stream
ftpStream.Close();
localFileStream.Close();
ftpRequest = null;
}
catch (Exception ex)
{
Console.WriteLine("Failed sending to " + host + "/" + remoteFile + " (" + ex.Message + ")");
}
}

You don't need to update progressRichTextBox in your upload method. Remove that parameter. You need to provide the worker object to your upload method and call worker.ReportProgress on it.

Related

Receiving Data only from one machine instead of all machine over TCP/IP

Our Client have a dialysis machine which use Ethernet TCP/IP Protocol and data transfer protocol is XML.It automatically connects to the our computer system by using the configured IP address and port number and sends unsolicited data messages every 60 seconds to our system. Client send data as XML Data Stream. Now I need to store data in XML file.
Below is my code.
Here now problem is, Client is sending data messages from four machines, However my code is capturing data from only one machine, Kindly suggest what I am missing here.
namespace NiproMI
{
class NiproListener
{
public static void GetXMLStream()
{
TcpListener server = null;
try
{
Int32 port = Int32.Parse(AppConfigValues.GetAppConfigValue("Port"));
IPAddress localAddr = IPAddress.Parse(AppConfigValues.GetAppConfigValue("IPAddress"));
server = new TcpListener(localAddr, port);
server.Start();
Byte[] bytes = new Byte[256];
String data = null;
while (true)
{
TcpClient client = server.AcceptTcpClient();
NetworkStream stream = client.GetStream();
string fileName = "NiproMI_" + DateTime.Now.ToString("dd-MM-yyyy--HH-mm-ss-ffff") + ".xml";
int i;
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
WriteToFile(data, fileName);
if (data.Contains("</Rec>"))
{
MoveInputFile(fileName);
fileName = "NiproMI_" + DateTime.Now.ToString("dd-MM-yyyy--HH-mm-ss-ffff") + ".xml";
}
}
}
}
catch (SocketException e)
{
MIEventLogs.WriteLog("SocketException: {0}" + e);
}
finally
{
server.Stop();
}
}
public static void WriteToFile(string sMessage, string fileName)
{
try {
DirectoryInfo logdirFile = new DirectoryInfo(System.Configuration.ConfigurationManager.AppSettings["XmlFilePath"].ToString());
string filePath = logdirFile.FullName;
if (File.Exists(Path.Combine(filePath, fileName)))
{
StreamWriter sw = null;
//Open File
FileStream fs = File.Open(Path.Combine(filePath, fileName), FileMode.Append, FileAccess.Write);
// generate a file stream with UTF8 characters
sw = new StreamWriter(fs, System.Text.Encoding.UTF8);
sw.WriteLine(sMessage);
sw.Close();
sw = null;
}
else
{
StreamWriter sw = null;
//Open File
FileStream fs = new FileStream(Path.Combine(filePath, fileName), FileMode.Create, FileAccess.Write);
// generate a file stream with UTF8 characters
sw = new StreamWriter(fs, System.Text.Encoding.UTF8);
sw.WriteLine(sMessage);
sw.Close();
sw = null;
}
}
catch (Exception e)
{
MIEventLogs.WriteLog( e.ToString());
}
}
private static void MoveInputFile(string sFileName)
{
string strSourceFullFileName = "";
string strDestFullFilename = "";
string movedFromFolder= AppConfigValues.GetAppConfigValue("XmlFilePath");
string movedToFolder = AppConfigValues.GetAppConfigValue("InputPath");
System.IO.DirectoryInfo objdestfolder = new System.IO.DirectoryInfo(movedToFolder);
System.IO.DirectoryInfo getsourceFile = new System.IO.DirectoryInfo(movedFromFolder);
string sourcePath = "";
string DestPath = "";
try
{
sourcePath = getsourceFile.FullName;
if (sourcePath[sourcePath.Length - 1] != '\\')
sourcePath += "\\";
if (File.Exists(sourcePath + sFileName))
strSourceFullFileName = sourcePath + sFileName;
DestPath = objdestfolder.FullName;
if (DestPath[DestPath.Length - 1] != '\\')
DestPath += "\\";
strDestFullFilename = DestPath + sFileName;
if ((File.Exists(strSourceFullFileName) == true) && (objdestfolder.Exists == true))
{
if (File.Exists(strDestFullFilename))
{
File.Delete(strDestFullFilename);
}
File.Move(strSourceFullFileName, strDestFullFilename);
}
else
{
throw new System.ApplicationException("Invalid destination folder to move retry file.");
}
}
catch (System.Exception ex)
{
}
finally
{
}
}
}
}
You need to hand off the client to another thread or task while you wait for a new client.
I suggest you change this code to be fully asynchronous, using tasks and await. Something like this should work.
public static Task GetXMLStream(CancellationToken cancel)
{
Int32 port = Int32.Parse(AppConfigValues.GetAppConfigValue("Port"));
IPAddress localAddr = IPAddress.Parse(AppConfigValues.GetAppConfigValue("IPAddress"));
using (var server = new TcpListener(localAddr, port))
{
server.Start();
while (!cancel.IsCancellationRequested)
{
TcpClient client = await server.AcceptTcpClientAsync(cancel);
Task.Run(async () => await ProcessClient(client, cancel));
}
server.Stop();
}
}
private static async Task ProcessClient(TcpClient client, CancellationToken cancel)
{
using (client)
using (NetworkStream stream = client.GetStream())
{
try
{
await LoopClientStream(stream, cancel);
}
catch (OperationCanceledException)
{ //
}
catch (SocketException e)
{
MIEventLogs.WriteLog("SocketException: {0}" + e);
}
}
}
Your code that reads the stream and writes it to a file should also be fully asynchronous. I will leave that to you. Make sure you pass the CancellationToken to each asynchronous function.
You should also be aware that the stream may not return </Rec> in a single read, it may be split over separate reads. You may want to find a better way of tracking the end of each packet of data

Uploading an image to FTP server on windows phone

Please Help! I've tried everything, i dont know what else to do. I just want to upload an image that the user chooses from their library to my websever.
I already have a code that uses webclient to upload to a url.
private void OnChoosePicturel(object sender, RoutedEventArgs e)
{
PhotoChooserTask task = new PhotoChooserTask();
task.Completed += task_Completed;
task.Show();
}
private void task_Completed(object sender, PhotoResult e)
{
if (e.TaskResult != TaskResult.OK)
return;
const int BLOCK_SIZE = 4096;
Uri uri = new Uri("URL");
WebClient wc = new WebClient();
NetworkCredential g = new NetworkCredential();
g.UserName = "USERNAME";
g.Password = "PASSWORD";
wc.Credentials = g;
wc.AllowReadStreamBuffering = true;
wc.AllowWriteStreamBuffering = true;
try
{
// what to do when write stream is open
wc.OpenWriteCompleted += (s, args) =>
{
using (BinaryReader br = new BinaryReader(e.ChosenPhoto))
{
using (BinaryWriter bw = new BinaryWriter(args.Result))
{
long bCount = 0;
long fileSize = e.ChosenPhoto.Length;
byte[] bytes = new byte[BLOCK_SIZE];
do
{
bytes = br.ReadBytes(BLOCK_SIZE);
bCount += bytes.Length;
bw.Write(bytes);
} while (bCount < fileSize);
}
}
};
}
catch(Exception t)
{
}
// what to do when writing is complete
wc.WriteStreamClosed += (s, args) =>
{
MessageBox.Show("Send Complete");
};
// Write to the WebClient
wc.OpenWriteAsync(uri, "STOR");
}
The problem is , the webclient class only works for "http" urls, but i need to connect and upload the file to an "ftp" url. How do i do this? Ive tried EVERYTHING. Nothing works.

Launch app to view pdf from the webview wp8

I'm trying to launch a pdf app viewer when the page on the webview is a pdf file, but i can´t find how to make this, is it possible?
You should read following article if you are not familiar with Async:
MSDN Asynchronous Programming with Async and Await
I couldn't test my app because my WP8 Phone is currently not available and I can't install an PDF reader on the emulator.
Call following method to start the download
WebClient pdfDownloader = null;
string LastFileName = ""; //To save the filename of the last created pdf
private void StartPDFDownload(string URL)
{
pdfDownloader = new WebClient(); //prevents that the OpenReadCompleted-Event is called multiple times
pdfDownloader.OpenReadCompleted += DownloadPDF; //Create an event handler
pdfDownloader.OpenReadAsync(new Uri(URL)); //Start to read the website
}
async void DownloadPDF(object sender, OpenReadCompletedEventArgs e)
{
byte[] buffer = new byte[e.Result.Length]; //Gets the byte length of the pdf file
await e.Result.ReadAsync(buffer, 0, buffer.Length); //Waits until the rad is completed (Async doesn't block the GUI Thread)
using (IsolatedStorageFile ISFile = IsolatedStorageFile.GetUserStoreForApplication())
{
try
{
LastFileName = "tempPDF" + DateTime.Now.Ticks + ".pdf";
using (IsolatedStorageFileStream ISFileStream = ISFile.CreateFile(LastFileName))
{
await ISFileStream.WriteAsync(buffer, 0, buffer.Length);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.HResult,
ex.Source, MessageBoxButton.OK);
//Catch errors regarding the creation of file
}
}
OpenPDFFile();
}
private async void OpenPDFFile()
{
StorageFolder ISFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
try
{
IStorageFile ISFile = await ISFolder.GetFileAsync(LastFileName);
await Windows.System.Launcher.LaunchFileAsync(ISFile);
//http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj206987%28v=vs.105%29.aspx
}
catch (Exception ex)
{
//Catch unknown errors while getting the file
//or opening the app to display it
}
}
To call these methods from your WebBrowser-Control you need to catch the navigating event.
YourWebBrowserControl.Navigating += YourWebBrowserControl_Navigating;
void YourWebBrowserControl_Navigating(object sender, NavigatingEventArgs e)
{
if(e.Uri.AbsolutPath.EndsWith("pdf"))
{
StartPDFDownload(e.Uri.ToString());
}
}
Don't forget that you'll have to delete the files created someday.

c# Stream progress just like .DownloadProgressChanged

So i have the following code:
WebClient webClient = new WebClient();
Stream data = webClient.OpenRead("http://awesomeurl.com/file.zip");
UnzipFromStream(data, #"c:/dir/");
And i would like to have the data of that stream in a progress bar, just like if you would use WebClient with .DownloadProgressChanged
I cant however seem to figure out how to make it work...
Please note: i am using ICSharpCode.SharpZipLib
UPDATE #1.1
Ok, i managed to get the following code to work (it downloads and unzips + the complete msg is shown), however the progress bar is not updating:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// first, we need to get the exact size (in bytes) of the file we are downloading
Uri url = new Uri(filename);
System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
response.Close();
// gets the size of the file in bytes
Int64 iSize = response.ContentLength;
// keeps track of the total bytes downloaded so we can update the progress bar
Int64 iRunningByteTotal = 0;
string outFolder = folder;
// use the webclient object to download the file
using (System.Net.WebClient webClient = new WebClient())
{
// open the file at the remote URL for reading
using (System.IO.Stream zipStream = webClient.OpenRead(filename))
{
ZipInputStream zipInputStream = new ZipInputStream(zipStream);
ZipEntry zipEntry = zipInputStream.GetNextEntry();
while (zipEntry != null)
{
String entryFileName = zipEntry.Name;
// to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
// Optionally match entrynames against a selection list here to skip as desired.
// The unpacked length is available in the zipEntry.Size property.
// Manipulate the output filename here as desired.
String fullZipToPath = Path.Combine(outFolder, entryFileName);
string directoryName = Path.GetDirectoryName(fullZipToPath);
if (directoryName.Length > 0)
Directory.CreateDirectory(directoryName);
// Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
// of the file, but does not waste memory.
// The "using" will close the stream even if an exception occurs.
using (FileStream streamWriter = File.Create(fullZipToPath))
{
int iByteSize = 0;
byte[] buffer = new byte[iSize]; // 4K is optimum
StreamUtils.Copy(zipInputStream, streamWriter, buffer);
while ((iByteSize = zipStream.Read(buffer, 0, buffer.Length)) > 0)
{
iRunningByteTotal += iByteSize;
// calculate the progress out of a base "100"
double dIndex = (double)(iRunningByteTotal);
double dTotal = (double)iSize;
double dProgressPercentage = (dIndex / dTotal);
int iProgressPercentage = (int)(dProgressPercentage * 100);
// update the progress bar
backgroundWorker1.ReportProgress(iProgressPercentage);
}
}
zipEntry = zipInputStream.GetNextEntry();
}
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("File download complete");
}

Can I create a download progress bar inside an iterator block?

I know progress bars by themselves have been already asked to death, but I'm having trouble with one. I need to download a file via FTP, I'm using WebClient, the downloaded data has to be saved to a byte array, but WebClient.DownloadDataAsync can't return it directly, so I have to use the DownloadDataCompleted method to acces the data. Everything up till there is ok, but the problem is that I can't "pause" the IEnumerator block without blocking the whole thread, and if I don't pause it, the app crashes because the byte array doesn't exist when it tries to access it. When the file to download was in http I used WWW and had no problems, but it had to be moved to FTP. Using WebClient.DownloadData works, but I was asked to include a progress bar. Anyway, here´s the code:
IEnumerator DownloadGame(Dictionary<string, string> settingsDict)
{
statusText = "Starting download...";
WebClient request = new WebClient();
request.Credentials = new NetworkCredential("user", "password");
request.DownloadDataCompleted += DownloadDataCompleted;
//byte[] fileData = request.DownloadData(settingsDict["downloadlink"]); This works, but is no good since it blocks the thread
request.DownloadDataAsync(new Uri(settingsDict["downloadlink"]),"somefilepath");
//do{}while(!downloadFinished); This also works but blocks the thread anyway
//Process the update
string tmpRoot = TMPFolder();
string tmpFolder = tmpRoot + Application.platform + settingsDict["latestVersion"] + "/";
if (!UnzipUpdate(fileData, tmpFolder))//fail here, in this case fileData is global
{
DeleteDirectory(tmpRoot);
yield break;
}
if (!ProcessUpdateData(tmpFolder))
{
DeleteDirectory(tmpRoot);
yield break;
}
DeleteDirectory(tmpRoot);
settingsDict["thisVersion"] = GetNextVersion();
}
void DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e){
fileData = e.Result;
downloadFinished = true;
}
you can use something like this based on a previous Stakoverflow post..
The easiest is to use BackgroundWorker and put your code into DoWork event handler. And report progress with BackgroundWorker.ReportProgress.
The basic idea:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var ftpWebRequest = (FtpWebRequest)WebRequest.Create("ftp://xxx.com");
ftpWebRequest.Method = WebRequestMethods.Ftp.UploadFile; //or DownLoad
using (var inputStream = File.OpenRead(fileName))
using (var outputStream = ftpWebRequest.GetRequestStream())
{
var buffer = new byte[1024 * 1024];
int totalReadBytesCount = 0;
int readBytesCount;
while ((readBytesCount = inputStream.Read(buffer, 0, buffer.Length)) > 0)
{
outputStream.Write(buffer, 0, readBytesCount);
totalReadBytesCount += readBytesCount;
var progress = totalReadBytesCount * 100.0 / inputStream.Length;
backgroundWorker1.ReportProgress((int)progress);
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}
Make sure WorkerReportsProgress is enabled
backgroundWorker2.WorkerReportsProgress = true;
With BackgroundWorker you can also easily implement upload cancellation.

Categories

Resources