I'm trying to use WebClient.DownloadFileTaskAsync to download a file so that I can make use of the download progress event handlers. The problem is that even though I'm using await on DownloadFileTaskAsync, it's not actually waiting for the task to finish and exits instantly with a 0 byte file. What am I doing wrong?
internal static class Program
{
private static void Main()
{
Download("http://ovh.net/files/1Gb.dat", "test.out");
}
private async static void Download(string url, string filePath)
{
using (var webClient = new WebClient())
{
IWebProxy webProxy = WebRequest.DefaultWebProxy;
webProxy.Credentials = CredentialCache.DefaultCredentials;
webClient.Proxy = webProxy;
webClient.DownloadProgressChanged += (s, e) => Console.Write($"{e.ProgressPercentage}%");
webClient.DownloadFileCompleted += (s, e) => Console.WriteLine();
await webClient.DownloadFileTaskAsync(new Uri(url), filePath).ConfigureAwait(false);
}
}
}
As others have pointed, The two methods shown are either not asynchronous or not awaitable.
First, you need to make your download method awaitable:
private async static Task DownloadAsync(string url, string filePath)
{
using (var webClient = new WebClient())
{
IWebProxy webProxy = WebRequest.DefaultWebProxy;
webProxy.Credentials = CredentialCache.DefaultCredentials;
webClient.Proxy = webProxy;
webClient.DownloadProgressChanged += (s, e) => Console.Write($"{e.ProgressPercentage}%");
webClient.DownloadFileCompleted += (s, e) => Console.WriteLine();
await webClient.DownloadFileTaskAsync(new Uri(url), filePath).ConfigureAwait(false);
}
}
Then, you either wait on Main:
private static void Main()
{
DownloadAsync("http://ovh.net/files/1Gb.dat", "test.out").Wait();
}
Or, make it asynchronous, too:
private static async Task Main()
{
await DownloadAsync("http://ovh.net/files/1Gb.dat", "test.out");
}
Related
WebClient DownloadFileAsync() does not work with the same URl and Credentials...
Any clue?
static void Main(string[] args)
{
try
{
var urlAddress = "http://mywebsite.com/msexceldoc.xlsx";
using (var client = new WebClient())
{
client.Credentials = new NetworkCredential("UserName", "Password");
// It works fine.
client.DownloadFile(urlAddress, #"D:\1.xlsx");
}
/*using (var client = new WebClient())
{
client.Credentials = new NetworkCredential("UserName", "Password");
// It y creats file with 0 bytes. Dunow why is it.
client.DownloadFileAsync(new Uri(urlAddress), #"D:\1.xlsx");
//client.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
}*/
}
catch (Exception ex)
{
}
}
You need to keep the program running while the async download completes, as it runs in another thread.
Try something like this, and wait for it to say completed before you hit enter to end the program:
static void Main(string[] args)
{
try
{
var urlAddress = "http://mywebsite.com/msexceldoc.xlsx";
using (var client = new WebClient())
{
client.Credentials = new NetworkCredential("UserName", "Password");
client.DownloadFileAsync(new Uri(urlAddress), #"D:\1.xlsx");
client.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
}
catch (Exception ex)
{
}
Console.ReadLine();
}
public static void Completed(object o, AsyncCompletedEventArgs args)
{
Console.WriteLine("Completed");
}
Depending what kind of app you're using this in, the main thread needs to keep running while the background thread downloads the file.
By declaring Main function as async, you can also use DownloadFileTaskAsync with await.
public static async void Main(string[] args)
{
var urlAddress = "http://mywebsite.com/msexceldoc.xlsx";
var fileName = #"D:\1.xlsx";
using (var client = new WebClient())
{
await client.DownloadFileTaskAsync(new Uri(urlAddress), fileName);
}
}
I have a WebApi self hosted console server over SSL.
The server takes care of creating the SSL certificates, adding them to the certificate store and binds the certificate to the port using netsh all on the fly.
The server has a simple controller that returns the string "Hello World" through HTTP GET.
I can access it through the browser without any problems and I am quite certain there is nothing wrong with the server code so I am only going to post the troubled client code here.
private static string url = #"https://localhost:4443/WebApi/Service/HelloWorld;
private static async Task GetHelloWorldRequest(string url)
{
using (HttpClient httpClient = new HttpClient(GetSSLHandler()))
{
HttpRequestMessage request = new HttpRequestMessage();
request.Method = HttpMethod.Get;
request.RequestUri = new Uri(url);
await httpClient
.SendAsync(request)
.ContinueWith((response)
=>
{
try
{
ProcessResponse(response);
}
catch (AggregateException agException)
{
throw new Exception("Error getting response: " + agException.Message);
}
}).ConfigureAwait(false);
}
}
private static void ProcessResponse(Task<HttpResponseMessage> response)
{
Console.WriteLine(response.Result.Content.ReadAsStringAsync().Result);
}
private static void ProcessResponseHeaders(Task<HttpResponseMessage> response)
{
Console.WriteLine(response.Result.Headers.ToString());
}
private static WebRequestHandler GetSSLHandler()
{
WebRequestHandler handler = new WebRequestHandler();
X509Certificate2 certificate = GetMyX509Certificate();
handler.ClientCertificates.Add(certificate);
return handler;
}
Now in my main routine I simply call this:
Console.WriteLine("Response headers:");
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
Task task = GetHelloWorldRequest(url);
task.Wait();
Now my problem is if I try to read the response content which should give me "Hello World" it gives me an empty string instead.
So I tried looking at the response headers and this is what I get:
It seems to be it is going through the negotiation phase and I don't know what to do from here.
Please advice. Thank you in advance.
EDIT:
Sorry the problem is with the server code. Simply uncomment the section calling httpBinding.ConfigureTransportBindingElement.
class SslHttpsSelfHostConfiguration : HttpSelfHostConfiguration
{
public SslHttpsSelfHostConfiguration(string baseAddress) : base(baseAddress) { }
public SslHttpsSelfHostConfiguration(Uri baseAddress) : base(baseAddress) { }
protected override BindingParameterCollection OnConfigureBinding(HttpBinding httpBinding)
{
httpBinding.Security.Mode = HttpBindingSecurityMode.Transport;
/*
httpBinding.ConfigureTransportBindingElement = (element =>
element.AuthenticationScheme =
AuthenticationSchemes.Negotiate);
*/
return base.OnConfigureBinding(httpBinding);
}
}
Please try running this:
var client = new HttpClient
{
BaseAddress = new Uri("https://localhost:4443/")
};
var result = await client.GetAsync("WebApi/Service/HelloWorld").ConfigureAwait(false);
var data = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
return data;
as your Request task.
And try changing the
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
to
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
I want to do this thing in windows phone 8.1 please suggest how to do.I have tried httpclient but didn't achieve the same result please suggest me something
private async void Button_Click(object sender, RoutedEventArgs e)
{
WebClient web = new WebClient();
web.Headers["content-type"] = "application/x-www-form-urlencoded";
string arg = "id=" + newone.Text;
// var postdata =js
string arg1 = "id=" + newone.Text;
//web.UploadStringAsync(new Uri("http://terasol.in/hoo/test.php/?id=&ncuavfvlqfd"), "GET");
web.UploadStringAsync(new Uri("http://terasol.in/hoo/test.php"), "POST", arg1);
web.UploadStringCompleted += web_uploadstringcomplete;
}
void web_uploadstringcomplete(object sender, UploadStringCompletedEventArgs e)
{
MessageBox.Show(e.Result);
}
thank you
Based on your sample code, and running it,
using the following code, I get the same value returned.
private static void Button_Click2(string id)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://terasol.in/");
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("id", id)
});
var result = client.PostAsync("/hoo/test.php", content).Result;
string resultContent = result.Content.ReadAsStringAsync().Result;
Console.WriteLine(resultContent);
}
}
I'm developping on Windows phone 8 and I would like to know if it's possible to manipulate data in the same method when we call DownloadStringCompleted of WebClient?
private void DownloadDataFromWebService(String uri)
{
WebClient wc = new WebClient();
wc.DownloadStringAsync(new Uri(uri));
wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted);
}
private void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
RootObject r = JsonConvert.DeserializeObject<RootObject>(e.Result);
List<Category> listeCategories = r.Result;
}
Thus, I would like to manage all code in only one method because I would like to return an object
For example,
private List<Category> GetCategories(String uri)
{
WebClient wc = new WebClient();
wc.DownloadStringAsync(new Uri(uri));
.....
.....
RootObject r = JsonConvert.DeserializeObject<RootObject>(e.Result);
return (List<Category>) r.Result;
}
Yes, that is possible, due to magic TaskCompletionSource class, http://msdn.microsoft.com/en-us/library/dd449174(v=vs.95).aspx . To download:
async Task<List<object>> getCategories(String uri)
{
var taskCompletionObj = new TaskCompletionSource<string>();
var wc= new webClient();
wc.DownloadStringAsync(new URI(uri, Urikind.Absolute)) += (o, e) =>
{
taskCompletionObj.TrySetResult(e.Result);
};
string rawString = await taskCompletionObj.Task;
RootObject r = JsonConvert.DeserializeObject<RootObject>(rawString);
return (List<Category>)r.Result;
}
To use: var x = await getCategories(myURI);
I tried this and i want that the source content of the website will be download to a string:
public partial class Form1 : Form
{
WebClient client;
string url;
string[] Search(string SearchParameter);
public Form1()
{
InitializeComponent();
url = "http://chatroll.com/rotternet";
client = new WebClient();
webBrowser1.Navigate("http://chatroll.com/rotternet");
}
private void Form1_Load(object sender, EventArgs e)
{
}
static void DownloadDataCompleted(object sender,
DownloadDataCompletedEventArgs e)
{
}
public string SearchForText(string SearchParameter)
{
client.DownloadDataCompleted += DownloadDataCompleted;
client.DownloadDataAsync(new Uri(url));
return SearchParameter;
}
I want to use WebClient and downloaddataasync and in the end to have the website source content in a string.
No need for async, really:
var result = new System.Net.WebClient().DownloadString(url)
If you don't want to block your UI, you can put the above in a BackgroundWorker. The reason I suggest this rather than the Async methods is because it is dramatically simpler to use, and because I suspect you are just going to stick this string into the UI somewhere anyway (where BackgroundWorker will make your life easier).
If you are using .Net 4.5,
public async void Downloader()
{
using (WebClient wc = new WebClient())
{
string page = await wc.DownloadStringTaskAsync("http://chatroll.com/rotternet");
}
}
For 3.5 or 4.0
public void Downloader()
{
using (WebClient wc = new WebClient())
{
wc.DownloadStringCompleted += (s, e) =>
{
string page = e.Result;
};
wc.DownloadStringAsync(new Uri("http://chatroll.com/rotternet"));
}
}
Using WebRequest:
WebRequest request = WebRequest.Create(url);
request.Method = "GET";
WebResponse response = request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
string content = reader.ReadToEnd();
reader.Close();
response.Close();
You can easily call the code from within another thread, or use background worer - that will make your UI responsive while retrieving data.