DownloadFileAsync 'blocks' in c#? - c#

When I use DownloadFileAsync, it seems to 'block' something. I need the program to be able to download more strings while the file is downloading (downloading a file, but user is still able to search a directory for links to download more files).
The UI is not 100% being blocked, but when the user clicks the 'search' button it doesn't work properly, nor do clicks in the DataGridView get handled. The search button however clears the DataGridView as programmed, but the await thing that I wrote to download the directory as a string (asynchronously with DownloadStringTaskAsync) does not work. However, when the download finishes, the search finally goes through and then populates the DataGridView, which seems like very abnormal behavior to me.
When I comment out the DownloadFileAsync, everything is able to perform normally again. I have also tried to comment out the event handlers that I have put in place, but this also does not fix the issue. I am not sure, thanks for any help.
Some code snippets:
Downloading the file:
var bmclient = new WebClient();
bmclient.DownloadFileAsync(new Uri(downloadURL), Path.Combine(Application.StartupPath, originalFileName + ".nexd"));
bmclient.DownloadProgressChanged += (o, e) =>
{
int rowIndex = -1;
DataGridViewRow row = form1.dataGridView2.Rows
.Cast<DataGridViewRow>()
.Where(r => r.Cells[0].Value.ToString().Equals(setID))
.First();
rowIndex = row.Index;
MethodInvoker action = () => form1.dataGridView2[2, rowIndex].Value = e.ProgressPercentage.ToString() + "%";
form1.BeginInvoke(action);
};
Searching the directory, which is being called by a button on the main form:
public static async Task<string> GetBloodcatSearch(string query)
{
var return_data = string.Empty;
try
{
using (var client = new WebClient())
{
return return_data = await client.DownloadStringTaskAsync(new Uri("directory/" + query));
}
}
catch (Exception e)
{
return null;
}
}

Related

Unity Firebase Storage - Check if file exists Async

After some advise around calls to firebase storage primarily how (from a sync POV) I should be checking to see if a file exists.
To set the context I am reading in a state file as json using the DownloadCoroutine function below and passing this into a JsonTextReader, this is working fine as long as the file exists in the first place (which as a new user it will not).
So then I wrote the below checkIfFile exists function which also works in a standalone capacity (Grabs the URL to prove that this file does in fact exist). Once this function has completed I then set a bool (SaveFileExists) to say this is/is not an existing file then go create one dependent on the state.
Where my problem lies is the order in which these functions are executed, I need the check to happen before any other methods are executed, they are both called in the LoadScene function currently. What I think I need to do is make the check an Async method returning a task? If so how would this look and where should I be calling it from, I have tried this but I think it keeps locking the main thread.
So the state right now is that because that bool doesnt change in time, the download of the storage file doesnt happen and the Json is never read in and throws an error, at the end of the console output the checkfile URL is outputted, any help would be great ,thanks.
private IEnumerator DownloadCoroutine(string path)
{
var storage = FirebaseStorage.DefaultInstance;
var storageReference = storage.GetReference(path);
if (SaveFileExists == true)
{
var DownloadTask = storageReference.GetBytesAsync(long.MaxValue);
yield return new WaitUntil(predicate: () => DownloadTask.IsCompleted);
byte[] fileContents = DownloadTask.Result;
retrievedSaveFile = Encoding.Default.GetString(fileContents);
Debug.Log("Downloading the save file");
}
else
{
createNewSaveFile(path);
}
}
Check to see if the Json file exists
private void CheckIfFileExists(string path)
{
var storage = FirebaseStorage.DefaultInstance;
var storageReference = storage.GetReference(path);
storageReference.GetDownloadUrlAsync().ContinueWith(task => {
if (!task.IsFaulted && !task.IsCanceled) {
Debug.Log("Download URL: " + task.Result);
SaveFileExists = true;
}
else{
Debug.Log("file doesnt exist so we create one");
}
});
}
Load scene
public IEnumerator LoadLastScene()
{
var User = FirebaseAuth.DefaultInstance.CurrentUser;
Debug.Log("USERID IS " + User.UserId.ToString());
CheckIfFileExists("Saves://" + User.UserId.ToString() + "saveFile.json");
yield return DownloadCoroutine("Saves://" + User.UserId.ToString() +
"saveFile.json");
}
The things you have to do is that
User authentication
Everything must be inside an async task function
check if the file exists
await storageRef.Root.Child(fUser.UserId).Child("Data").GetDownloadUrlAsync().ContinueWith(async task2 =>
{
if (task2.IsFaulted || task2.IsCanceled)
{
Debug.Log("<color=Red>File Not Exists</color>");
}
else
{
Debug.Log("<color=green>File Exists</color>");
await DownloadData();
}
});

GeckoFx 60 Download + Open File

I want the embedded GeckoFx 60 to download a file and then open it with the default app.
By default it seems like GeckoFx does not do anything when the client requests to download a file.
To handle the download request I enabled an event handler:
LauncherDialog.Download += LauncherDialog_Download;
Then I found two possibilities to download or open a file via the HelperAppLauncher.
This one saves the requested file to a temp folder and opens it:
private void LauncherDialog_Download(object sender, LauncherDialogEvent e)
{
// direct open, file will be stored in C:\Users\Username\AppData\Local\Temp\
e.HelperAppLauncher.LaunchWithApplication(null, false);
}
I did not find a way to configure the save path. This other possible solution allows me to set the save path myself:
private void LauncherDialog_Download(object sender, LauncherDialogEvent e)
{
nsILocalFileWin objTarget = Xpcom.CreateInstance<nsILocalFileWin>("#mozilla.org/file/local;1");
var downloadPath = #Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\CustomFolder\\" + e.Filename;
using (nsAString tmp = new nsAString(downloadPath))
{
objTarget.InitWithPath(tmp);
}
e.HelperAppLauncher.SaveToDisk(objTarget, false);
Task.Run(() =>
{
Thread.Sleep(3000);
System.Diagnostics.Process.Start(downloadPath);
});
}
That Task.Run() works, but is quite ugly and error prone. I could not find a better solution though. I tried adding a WebProgressListener like this:
var webProgressListener = new WebProgressListener();
webProgressListener.OnStatusChangeCallback+= OnStatusChangeCallback;
e.HelperAppLauncher.SetWebProgressListener(webProgressListener);
webProgressListener.IsListening is true, but my method OnStatusChangeCallback is never called. Am I doing something wrong? Is there a newer way?
How can I get notified that the download is completed?
Or how do I set the path for LaunchWithApplication?
Not the best solution but here is my solution :
Task.Run(() =>
{
long sizefirst = 0;
while (true)
{
Thread.Sleep(1000);
if (File.Exists(downloadPath))
{
if (sizefirst == 0)
{
sizefirst = new FileInfo(downloadPath).Length;
continue;
}
long len_now = new FileInfo(downloadPath).Length;
if (len_now > sizefirst)
{
sizefirst = len_now;
continue;
}
else
{
System.Diagnostics.Process.Start(downloadPath);
break;
}
}
}
});

System.Threading.ThreadStateException OpenFileDialog

Today, I was trying to make an adb client in C# with a decent GUI.
So, i 've done some research and found SharpAdbClient.
To do a file push, I use var file = openFileDialog2.ShowDialog(); to select a file.
But if I try pushing a big file, the GUI stops responding (how it's supposed to be).
So, to solve this issue, I've set up a thread that does the push but I've got a ThreadStateException when I try to launch the OpenFileDialog.
Here's an example code:
private void button4_Click(object sender, EventArgs e)
{
Thread pushFile = new Thread(push);
pushFile.Start();
}
private void push()
{
var device = AdbClient.Instance.GetDevices().First();
var file = openFileDialog2.ShowDialog();
var p = new Progress<int>(Progress_Bar);
String newPath = textBox2.Text;
if (file == DialogResult.OK)
{
String filePath = openFileDialog2.InitialDirectory + openFileDialog2.FileName;
using (SyncService service = new SyncService(new AdbSocket(new IPEndPoint(IPAddress.Loopback, AdbClient.AdbServerPort)), device))
using (Stream stream = File.OpenRead(filePath))
{
service.Push(stream, newPath, 444, DateTime.Now, p, CancellationToken.None);
}
}
}
You can't invoke UI-methods on threads that are not the GUI thread. You'll have to dispatch that to the correct thread. In WinForms, you'd use Invoke, BeginInvoke and similar to do that.
Have a look at the Control.Invoke documentation for more information on this.

detect when uploadValues is completed?

I want to display a message box after posting data to a remote php file..
PS: The php file return the string "END" when the data is completely processed
if (1 == outputToGui)
{
CompressFile("allFilesList.txt");
byte[] allFilesList = File.ReadAllBytes("allFilesList.txt.gz");
string URIx = "http://example.com/post.php";
System.Collections.Specialized.NameValueCollection data = new System.Collections.Specialized.NameValueCollection();
data.Add("serial", serial);
data.Add("data", Convert.ToBase64String(allFilesList));
using (WebClient tayba = new System.Net.WebClient())
{
try
{
tayba.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
tayba.Proxy = null;
tayba.UploadValues(URIx, "POST", data);
}
catch (Exception E) { }
}
}
MessageBox.Show("upload completed"); // this message show up before the php file process the posted data sometimes.. ?!!!!
The problem is that the message box show up before the php file process the posted data sometimes.. ?!!!!
Thats because operation is asynchronous. Upload might still be in progress when messagebox is called.
Search webclient for correct completion event and add your message there. META: _webClient.eventName += (sender, args) => MessageBox.Show("Ta-dah!");
Assign event listener before you start the upload.

FileUpload watin

I need to upload a file in a website using watin. The problem is that setting the direction of the file, like this:
browser.FileUpload(Find.ById("ctl00_cpContent_FileUpload1")).Set(DIRECCION_XML + "plantilla.txt");
doesnt work. Because this, I need to handle the windows popup that appear and fill the direction of the file to upload. I dont know how to do it... I were searching info of FileUploadHandler, but i cant get it.
There is more option than that? Pls, help me with a possible code to do it.
Really thanks
The FileUploadHandler works great. I have it running in production mode with thousands of files being uploaded every day and I haven't had any issues with it so far.
This is the way it needs to be implemented:
EDIT: (I forgot to include the uploadDialog object)
IntPtr hwndTmp = (IntPtr)FindWindow("#32770","Select file(s) to upload"); // or whatever the window text says when you are opening that upload window)
Window uploadDialog = new Window(hwndTmp);
UploadFileDialogHandler uploadFile = new UploadFileDialogHandler(_toBeSent.FileToSent);
_browser.AddDialogHandler(uploadFile);
uploadFile.HandleDialog(uploadDialog);
uploadFile = null;
That will take care of the upload process. when you need to upload the file just those lines will take care of everything (loop thru all open dialogs, find the right one, find the text field, enter the name for you and click the Ok button. On top of that you need to create another class that will be the UploadFileDialogHandler:
public class UploadFileDialogHandler : BaseDialogHandler
{
private const int WmSettext = 0x000C;
private string fileName;
private bool _processed = false;
public override bool HandleDialog(Window window)
{
var button = GetOpenButton(window);
if (button != null)
{
if (_processed == false)
{
var fileNameHandle = NativeMethods.GetChildWindowHwnd(window.Hwnd, "Edit");
var fileNameHwnd = new Hwnd(fileNameHandle);
fileNameHwnd.SetFocus();
_processed = true;
//MessageBox.Show("About to send " + fileName);
fileNameHwnd.SendString(fileName);
button.Click();
}
return true;
}
else
{
return false;
}
}
public UploadFileDialogHandler(string file)
{
fileName = "";
fileName = file;
//MessageBox.Show("Setting filename: " + fileName);
}
public override bool CanHandleDialog(Window window)
{
return GetOpenButton(window) != null;
}
private WinButton GetOpenButton(Window window)
{
var windowButton = new WindowsEnumerator().GetChildWindows(window.Hwnd, w => w.ClassName == "Button" && new WinButton(w.Hwnd).Title == "&Open").FirstOrDefault();
if (windowButton == null)
return null;
else
return new WinButton(windowButton.Hwnd);
}
}
}
You can just copy and paste that class inside your program and with the 4 lines of code above it will take care of the rest for you. In case you need more information there's a good amount of information on the WatIn file source code but it could be a little bit challenging to follow if you don't understand the Windows API.
Hope this helps.
This command work for me fine: browser.FileUpload(Find.ById("FormImage")).Set("C:\\Pictures\\11.PNG");
Try it

Categories

Resources