3

I am using the WebClient.DownloadFileAsync() method, and wanted to know how can i pass a parameter to the WebClient.DownloadFileCompleted event (or any other event for that matter), and use it in the invoked method.

My code:

public class MyClass
{
    string downloadPath = "some_path";
    void DownloadFile()
    {
        int fileNameID = 10;
        WebClient webClient = new WebClient();
        webClient.DownloadFileCompleted += DoSomethingOnFinish;
        Uri uri = new Uri(downloadPath + "\" + fileNameID );
        webClient.DownloadFileAsync(uri,ApplicationSettings.GetBaseFilesPath +"\" + fileNameID); 
    }

    void DoSomethingOnFinish(object sender, AsyncCompletedEventArgs e)
    {
        //How can i use fileNameID's value here?
    }

}

How can I pass a parameter to DoSomethingOnFinish()?

trahane
  • 701
  • 6
  • 16
mihaa123
  • 1,012
  • 9
  • 19
  • The only way I can think of right now is, that you can hold the file name in a global private field and access it in `DoSomethingOnFinish` – Christoph K Aug 29 '16 at 11:27
  • @ ChristophKn that was my original solution, but thought maybe there is something more elegant :) When dealing with several downloads this becomes messy – mihaa123 Aug 29 '16 at 12:33

1 Answers1

11

You can use webClient.QueryString.Add("FileName", YourFileNameID); to add extra information.

Then to access it in your DoSomethingOnFinish function,

use string myFileNameID = ((System.Net.WebClient)(sender)).QueryString["FileName"]; to receive the file name.

This is what the code should look like:

string downloadPath = "some_path";
void DownloadFile()
{
    int fileNameID = 10;
    WebClient webClient = new WebClient();
    webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(DoSomethingOnFinish);
    webClient.QueryString.Add("fileName", fileNameID.ToString());
    Uri uri = new Uri(downloadPath + "\\" + fileNameID);
    webClient.DownloadFileAsync(uri,ApplicationSettings.GetBaseFilesPath +"\\" + fileNameID); 
}

void DoSomethingOnFinish(object sender, AsyncCompletedEventArgs e)
{
    //How can i use fileNameID's value here?
    string myFileNameID = ((System.Net.WebClient)(sender)).QueryString["fileName"];
}

Even if this should work, you should be using Unity's UnityWebRequest class. You probably haven't heard about it but this is what it should look like:

void DownloadFile(string url)
 {
     StartCoroutine(downloadFileCOR(url));
 }

 IEnumerator downloadFileCOR(string url)
 {
     UnityWebRequest www = UnityWebRequest.Get(url);

     yield return www.Send();
     if (www.isError)
     {
         Debug.Log(www.error);
     }
     else
     {
         Debug.Log("File Downloaded: " + www.downloadHandler.text);

         // Or retrieve results as binary data
         byte[] results = www.downloadHandler.data;
     }
 }
Programmer
  • 121,791
  • 22
  • 236
  • 328
  • Thanks for the quick response, will check your solution now. The goal was to implement downloads on a separate thread. Is UnityWebRequest something i can use outside the main thread? – mihaa123 Aug 29 '16 at 12:36
  • First, I want you to understand that the code in your question is not using `Thread`. You are using `Async` which is different from `Thread`. Although, `Async` is easier to use than `Thread`. As for `UnityWebRequest`, you ca't use it in another Thread. You can't use Unity's API in another Thread. Although, both code in my answer are equivalent and they both use `Async`. – Programmer Aug 29 '16 at 13:06
  • 1
    This is from MSDN: "The file is downloaded asynchronously using thread resources that are automatically allocated from the thread pool." Doesn't this mean this function internally uses a worker thread to download the file? @Programmer – mihaa123 Aug 30 '16 at 06:19
  • Thanks, i will read up on the subject. Regarding my original question- is there any way i can pass a ref to an object with the sender object? Similar to the way you suggested with the int type? – mihaa123 Aug 30 '16 at 08:38
  • "Similar to the way you suggested with the int type?" I think that No built in way. `QueryString` works with strings not int. There is a magical way to do this. Create a list that will hold that object reference. When you call the DownloadFile function, add that object to the list then add the list's index, `QueryString.Add`. When DoSomethingOnFinish is called, use that index to get the object reference from the List. You can also do this with a dictionary – Programmer Aug 30 '16 at 09:00
  • 1
    `webClient.QueryString.Add( keyName, value );` was just the magic I needed. Thank you – Kraang Prime Dec 19 '16 at 05:19