WebClient.DownloadStringAsync URL not working - c#

I've got an issue about webclient on windowsphone 8.
I've hit an API use webclient on my code.
public void LoadData(bool refresh)
{
IsLoading = true;
WebClient webclient = new WebClient();
webclient.DownloadStringCompleted += webclient_DownloadStringCompleted;
webclient.DownloadStringAsync(new Uri("http://api.xxxx.com/getQuestion"));
}
public void webclient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
RootObject deserCustomers = JsonConvert.DeserializeObject<RootObject>(e.Result);
foreach (var cust in deserCustomers.data)
{
Debug.WriteLine(cust.title);
int length = cust.question.Length;
string subquestion;
if (length > 100) { subquestion = cust.question.Substring(0, 100); }
else { subquestion = cust.question; }
_questiondata.Add(new QuestionItem() { Title = cust.title, Question_Str = subquestion, Slug = cust.slug });
}
IsLoading = false;
}
It's work for the first time and the data is exactly same as web. But when the web update with new question, and I try to call method LoadData for the second time, the data not same as web. the new update question on web does not appear in my apps (windows phone).
What should I do, Is there any cache that make my result not updated like on web?
Thanks a lot.

I've got a help and it Solved. try this:
public void LoadData(bool refresh)
{
IsLoading = true;
WebClient webclient = new WebClient();
webclient.DownloadStringCompleted += webclient_DownloadStringCompleted;
Random random = new Random();
webclient.DownloadStringAsync(new Uri("http://api.xxxx.com/getQuestion?random="+ random.Next().ToString()));
}

Related

C# Launcher based on WebClient

I'm creating simple launcher for my other application and I need advise on logical part of the program. Launcher needs to check for connection, then check for file versions (from site), compare it with currently downloaded versions (if any) and if everything is alright, start the program, if not, update (download) files that differs from newest version. The files are:
program.exe, config.cfg and mapFolder. The program.exe and mapFolder must be updated, and config.cfg is only downloaded when there is no such file. Additionaly mapFolder is an folder which contains lots of random files (every new version can have totally different files in mapFolder).
For the file version I thought I would use simple DownloadString from my main site, which may contain something like program:6.0,map:2.3, so newest program ver is 6.0 and mapFolder is 2.3. Then I can use FileVersionInfo.GetVersionInfo to get the version of current program (if any) and include a file "version" into mapFolder to read current version.
The problem is I dont know how to download whole folder using WebClient and what's the best way to do what I want to do. I've tried to download the mapFolder as zip and then automatically unpack it, but the launcher need to be coded in .net 3.0.
Here is my current code, that's just a prototype to get familiar with whole situation, dont base on it.
`
WebClient wc = new WebClient();
string verifySite = "google.com/downloads/version";
string downloadSite = "google.com/downloads/program.exe";
Uri verifyUri, downloadUri = null;
string userVer, currVer = "";
string downloadPath = Directory.GetCurrentDirectory();
string clientName = "program.exe";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(FileDownloaded);
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(FileDownloadProgress);
chckAutorun.Checked = Properties.Settings.Default.autorun;
checkConnection();
if(!checkVersion())
downloadClient();
else
{
pbDownload.Value = 100;
btnPlay.Enabled = true;
lblProgress.Text = "updated";
if (chckAutorun.Checked)
btnPlay.PerformClick();
}
}
private bool checkConnection()
{
verifyUri = new Uri("http://" + verifySite);
downloadUri = new Uri("http://" + downloadSite);
WebRequest req = WebRequest.Create(verifyUri);
try
{
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
return true;
}
catch { }
verifyUri = new Uri("https://" + verifySite);
downloadUri = new Uri("https://" + downloadUri);
req = WebRequest.Create(verifyUri);
try
{
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
return true;
}
catch { }
return false;
}
private void downloadClient()
{
try
{
wc.DownloadFileAsync(downloadUri, Path.Combine(downloadPath, clientName));
}
catch { }
}
private bool checkVersion()
{
lblProgress.Text = "checking for updates";
try
{
currVer = FileVersionInfo.GetVersionInfo(Path.Combine(downloadPath, clientName)).FileVersion;
}
catch {
currVer = "";
}
try
{
userVer = wc.DownloadString(verifyUri);
}
catch {
userVer = "";
}
return currVer == userVer && currVer != "";
}
private void FileDownloaded(object sender, AsyncCompletedEventArgs e)
{
btnPlay.Enabled = true;
lblProgress.Text = "updated";
if (chckAutorun.Checked)
btnPlay.PerformClick();
}
private void FileDownloadProgress(object sender, DownloadProgressChangedEventArgs e)
{
long received = e.BytesReceived / 1000;
long toReceive = e.TotalBytesToReceive / 1000;
lblProgress.Text = string.Format("{0}KB {1}/ {2}KB", received, Repeat(" ", Math.Abs(-5 + Math.Min(5, received.ToString().Length))*2), toReceive);
pbDownload.Value = e.ProgressPercentage;
}
private void btnPlay_Click(object sender, EventArgs e)
{
btnPlay.Enabled = false;
if(checkVersion())
{
lblProgress.Text = "Starting...";
Process.Start(Path.Combine(downloadPath, clientName));
this.Close();
}
else
{
downloadClient();
}
}
public static string Repeat(string instr, int n)
{
if (string.IsNullOrEmpty(instr))
return instr;
var result = new StringBuilder(instr.Length * n);
return result.Insert(0, instr, n).ToString();
}
private void chckAutorun_CheckedChanged(object sender, EventArgs e)
{
Properties.Settings.Default.autorun = chckAutorun.Checked;
Properties.Settings.Default.Save();
}`
I've managed to achieve what I need by enabling autoindex on web server and download string of files in folder ending with .map .
string mapSite = wc.DownloadString(new Uri("http://" + mapsSite));
maps = Regex.Matches(mapSite, "<a href=\"(.*).map\">");
foreach (Match m in maps)
{
string mapName = m.Value.Remove(0, 9).Remove(m.Length - 11);
downloaded = false;
wc.DownloadFileAsync(new Uri("http://" + mapsSite + mapName), Path.Combine(downloadPath, #"mapFolder/" + mapName));
while (!downloaded) { }
}

Google Drive REST API Windows Forms login

I'm having a problem retrieving the access token from the redirect uri. When I try my coded procedure on my mozilla I get redirected to my localhost with the access token, but how do I instantiate this with my webBrowser in C#?
My current code looks like this:
public partial class Form1 : Form
{
public string client_id = "CLIENT_ID";
public string client_secret= "CLIENT_SECRET";
public string redirect_uri = "http://localhost:5050";
public Form1()
{
InitializeComponent();
webBrowser.AllowNavigation = true;
webBrowser.DocumentCompleted += webBrowser_DocumentCompleted;
webBrowser.Navigate(String.Format("https://accounts.google.com/o/oauth2/auth?response_type=code&scope=email+profile&redirect_uri={0}&client_id={1}&hl=de&from_login=1&as=d832bdaf61552d&pli=1&authuser=0"
,redirect_uri, client_id));
}
void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wb = sender as WebBrowser;
//MessageBox.Show(wb.Url.ToString());
if (wb.Url.ToString().StartsWith("http://localhost"))
{
String[] s = wb.Url.ToString().Split('=');
string authCode = s[s.Length - 1];
MessageBox.Show("auth Code: " + authCode);
//WebClient wc = new WebClient();
//var data = new NameValueCollection();
//data["code"] = authCode;
//data["client_id"] = client_id;
//data["client_secret"] = client_secret;
//data["redirect_uri"] = "http://localhost:5050";
//data["grant_type"] = "authorization_code";
//var response = wc.UploadValues("accounts.google.com/o/oauth2/token", "POST", data);
//foreach (byte a in response)
//{
// MessageBox.Show(a.ToString());
//}
}
}
If you know how to do this with the GoogleDrive API please share it with me.
Please Use UIWebBrowser instead of WebBrowser and your code should like this.
public Form1()
{
InitializeComponent();
UIWebBrowser.AllowNavigation = true;
UIWebBrowser.DocumentCompleted += webBrowser_DocumentCompleted;
UIWebBrowser.Navigate(String.Format("https://accounts.google.com/o/oauth2/auth?response_type=code&scope=email+profile&redirect_uri={0}&client_id={1}&hl=de&from_login=1&as=d832bdaf61552d&pli=1&authuser=0"
,redirect_uri, client_id));
}
void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (e.Url.AbsoluteUri.StartsWith("http://localhost"))
{
// Redirect so we end up with a blank web browser control
UIWebBrowser.Navigate("about:blank");
code = e.Url.Query;
}
}

How do I check if WebClient download is completed before I execute a function?

I am trying to get to JSON files from different URLs. How do I make sure both files are downloaded completely before I try to execute something else.
My code looks something like this:
WebClient Url1 = new WebClient();
Url1.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Url1_DownloadStringCompleted);
Url1.DownloadStringAsync(new Uri("http://example.com"));
WebClient Url2 = new WebClient();
Url2.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Url2_DownloadStringCompleted);
Url2.DownloadStringAsync(new Uri("http://anotherexample.com"));
DoSomethingWithJson();
void Url1_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
return;
json1 = JObject.Parse(e.Result);
}
void Url2_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
return;
json2 = JObject.Parse(e.Result);
}
Right now, what happens is json1 and json2 returns null values whenever I try to display them in a MessageBox inside DoSomethingWithJson(), and I am assuming this might be because they haven't been downloaded completely.
The DownloadStringAsync() method is returning before the string is downloaded because it's an asynchronous method. If you move the DoSomethingWithJson() method to your completed handlers then it will be called once the request is completed. You may want to add logic to the DoSomethingWithJson() method so that it only does it's work if all the variables it needs are populated (If indeed you need them all to be populated before you start doing anything else).
WebClient Url1 = new WebClient();
Url1.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Url1_DownloadStringCompleted);
Url1.DownloadStringAsync(new Uri("http://example.com"));
WebClient Url2 = new WebClient();
Url2.DownloadStringCompleted += new DownloadStringCompletedEventHandler(Url2_DownloadStringCompleted);
Url2.DownloadStringAsync(new Uri("http://anotherexample.com"));
var json1Done = false;
var json2Done = false;
void Url1_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
return;
json1 = JObject.Parse(e.Result);
json1Done = true;
if(json1Done && json2Done)
{
DoSomethingWithJson();
}
}
void Url2_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
return;
json2 = JObject.Parse(e.Result);
json2Done = true;
if(json1Done && json2Done)
{
DoSomethingWithJson();
}
}
Alternatively, if you are using .Net 4.5 then you could use the new async/await features:
WebClient Url1 = new WebClient();
var json1Task = Url1.DownloadStringTaskAsync(new Uri("http://example.com"));
WebClient Url2 = new WebClient();
var json2Task = Url2.DownloadStringTaskAsync(new Uri("http://anotherexample.com"));
json1 = await json1Task;
json2 = await json2Task;
DoSomethingWithJson();

Facebook logout Windows Phone Application without opening WebBrowser

I am trying to develop a Windows Phone 7 application using Facebook login and logout operations. I found Facebook SDK and used it in order to carry out login, by opening WebBrowser. The user enters credentials to this browser and logs in successfully. Moreover, I managed to login the user without using any SDK, just using http requests, like the SDK actually does. However, I want to logout users without using any WebBrowser, but just clicking a button for example. There are so many solutions in the web suggesting that I should open web browser and navigate it to a certain URL in order to logout. However, this is not what I want. I think there should be a way to logout by clearing cookies, which I dont exactly know how to do, or any other that you suggest. Some part of my code below:
private static String appID = "";
private static String appSecret = "";
public static void login(String[] permissions)
{
try
{
permissionArray = permissions;
popup = new Popup();
popup.Height = 480;
popup.Width = 480;
popup.VerticalOffset = 100;
FacebookLoginUserControl control = new FacebookLoginUserControl();
control.facebookWebBrowser.Loaded += new RoutedEventHandler(webBrowser_Loaded);
control.facebookWebBrowser.Navigated += new EventHandler<System.Windows.Navigation.NavigationEventArgs>(webBrowser_Navigated);
popup.Child = control;
popup.IsOpen = true;
}
catch (Exception e)
{
//handle
}
}
private static void webBrowser_Loaded(Object sender, RoutedEventArgs e)
{
WebBrowser wb = (WebBrowser)sender;
String loginUrl = GetFacebookLoginUrl();
wb.Navigate(new Uri(loginUrl));
}
private static String GetFacebookLoginUrl()
{
String permissionString = String.Empty;
if (permissionArray.Length > 0)
permissionString = String.Join(",", permissionArray);
var uriParams = new Dictionary<string, string>() {
{"client_id", appID},
{"response_type", "token"},
{"scope", permissionString},
{"redirect_uri", "http://www.facebook.com/connect/login_success.html"},
{"display", "touch"}
};
StringBuilder urlBuilder = new StringBuilder();
foreach (var current in uriParams)
{
if (urlBuilder.Length > 0)
{
urlBuilder.Append("&");
}
var encoded = HttpUtility.UrlEncode(current.Value);
urlBuilder.AppendFormat("{0}={1}", current.Key, encoded);
}
var loginUrl = "http://www.facebook.com/dialog/oauth?" + urlBuilder.ToString();
return loginUrl;
}
private static void webBrowser_Navigated(Object sender, System.Windows.Navigation.NavigationEventArgs e)
{
if (string.IsNullOrEmpty(e.Uri.Fragment)) return;
if (e.Uri.AbsoluteUri.Replace(e.Uri.Fragment, "") == "http://www.facebook.com/connect/login_success.html")
{
string text = HttpUtility.HtmlDecode(e.Uri.Fragment).TrimStart('#');
var pairs = text.Split('&');
foreach (var pair in pairs)
{
var kvp = pair.Split('=');
if (kvp.Length == 2)
{
if (kvp[0] == "access_token")
{
accessToken = kvp[1];
MessageBox.Show("Access granted");
RequestUserProfile();
}
}
}
if (string.IsNullOrEmpty(accessToken))
{
MessageBox.Show("Unable to authenticate");
}
popup.IsOpen = false;
}
}
private static void RequestUserProfile()
{
var profileUrl = string.Format("https://graph.facebook.com/me?access_token={0}", HttpUtility.UrlEncode(accessToken));
request = (HttpWebRequest)HttpWebRequest.Create(new Uri(profileUrl));
request.Method = "GET";
request.BeginGetResponse(result =>
{
try
{
var resp = (result.AsyncState as HttpWebRequest).EndGetResponse(result);
using (var strm = resp.GetResponseStream())
{
StreamReader sr = new StreamReader(strm);
var responseString = sr.ReadToEnd();
}
}
catch (Exception ex)
{
//
}
}, request);
}
Any Ideas to solve the problem.
Thanks in advance
What's actually so spooky in using webBrowser? If you programmatically create a WebBrowser object, it won't be visible, unless you'd add it somewhere on form/page. If you want to clear cookies for Facebook, the solution will be something like that:
// Can be invoked from your button_click event
public void TryLogout()
{
webBrowser = new WebBrowser();
Uri uri = new Uri("http://m.facebook.com/home.php?r", UriKind.Absolute);
webBrowser.LoadCompleted += new LoadCompletedEventHandler(webBrowser_TryLogoutLoadCompleted);
webBrowser.Navigate(uri);
}
And then:
private void webBrowser_TryLogoutLoadCompleted(object sender, EventArgs e)
{
try
{
var cookies = webBrowser.GetCookies();
foreach (Cookie cookie in cookies)
{
if (cookie.Domain.Contains("m.facebook.com"))
{
cookie.Discard = true;
cookie.Expired = true;
}
}
// we've just cleaned up cookies
}
finally
{
webBrowser.LoadCompleted -= webBrowser_TryLogoutLoadCompleted;
}
}
Hope this helps.
GetCookies method

How can I get the URL in OpenReadCompletedEvent when I use webclient

How can I get the URL in OpenReadCompletedEvent when I use webclient.
WebClient webClient = new WebClient();
webClient.OpenReadAsync(url); // in event method I want get this url
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(CardInfoDown_Completed);
private void CardInfoDown_Completed(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
using (System.IO.StreamReader reader = new System.IO.StreamReader(e.Result))
{
// I want get the url here,
// How to do this?
string strStream = reader.ReadToEnd();
}
}
}
Thank you!
WebClient webClient = new WebClient();
webClient.BaseAddress = "http://hhh.com";
webClient.OpenReadAsync(new Uri("http://hhh.com")); // in event method I want get this url
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(CardInfoDown_Completed);
And:
private void CardInfoDown_Completed(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
using (System.IO.StreamReader reader = new System.IO.StreamReader(e.Result))
{
// I want get the url here,
// How to do this?
var client = sender as WebClient;
if (client != null)
{
var url = client.BaseAddress; //returns hhh.com
}
string strStream = reader.ReadToEnd();
}
}
Anton Sizikov's solution is good, but will only work if the URL is absolute (like http://hhh.com). If using a relative URL, .NET will automatically merge the base address with the relative URL (therefore potentially resulting in an invalid URL).
To send a value to the OpenReadCompleted event handler, you're supposed to use this OpenRead overload to provide a custom token (in this case, your URL): http://msdn.microsoft.com/en-us/library/ms144212(v=vs.95).aspx
WebClient webClient = new WebClient();
webClient.OpenReadAsync(new Uri("http://hhh.com"), "http://hhh.com");
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(CardInfoDown_Completed);
Then to retrieve the value:
private void CardInfoDown_Completed(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
using (System.IO.StreamReader reader = new System.IO.StreamReader(e.Result))
{
var url = (string)e.UserState;
string strStream = reader.ReadToEnd();
}
}
}
For me even a simpler variation from the above works fine
private void CardInfoDown_Completed(object sender, DownloadStringCompletedEventArgs e)
{
string url;
if (e.Error == null)
{
url = (string)e.UserState;
}
// ...
}

Categories