如何异步地检索多个网站?
如何异步地检索多个网站?
使用Silverlight Windows Phone 8.1项目\n我正在尝试从网站加载数据。然而,我必须首先在该网站进行身份验证。\n所以我对该网站进行了一次提交,使用了稍作修改的CookieAwareWebClient,来自这里。\n
class CookieAwareWebClient : WebClient { public CookieContainer Cookies = new CookieContainer(); protected override WebRequest GetWebRequest(Uri address) { var request = base.GetWebRequest(address); if (request is HttpWebRequest) (request as HttpWebRequest).CookieContainer = Cookies; return request; } }
\n现在我使用WebClient发送带有用户名和密码的POST请求,并在我的DownloadStringCompleted事件处理程序中继续获取我的网站数据。\n到目前为止都还好。\n现在我想扩展一下,获取多个网站。\n我不必一次获取它们,事实上,最好一个接一个地获取它们。\n但是我不知道如何处理这个问题。\n到目前为止我的代码如下:\n
using System; using System.Net; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using Windows.Web.Http; using Microsoft.Phone.Shell; using StackOverflowApp.Resources; namespace StackOverflowApp { public partial class MainPage { private const string URL_DATES = @"/subsite/dates"; private const string URL_RESULTS = @"/subsite/results"; private readonly ApplicationBarIconButton btn; private int runningOps = 0; //Regex's to parse websites private readonly Regex regexDates = new Regex(AppResources.regexDates); private readonly Regex regexResults = new Regex(AppResources.regexResults); private readonly CookieAwareWebClient client = new CookieAwareWebClient(); private int status; // Konstruktor public MainPage() { InitializeComponent(); btn = ((ApplicationBarIconButton)ApplicationBar.Buttons[0]); // = application/x-www-form-urlencoded client.Headers[HttpRequestHeader.ContentType] = AppResources.ContentType; client.UploadStringCompleted += UploadStringCompleted; client.DownloadStringCompleted += DownloadStringCompleted; } private void GetSite() { const string POST_STRING = "name={0}&password={1}"; var settings = new AppSettings(); if (settings.UsernameSetting.Length < 3 || settings.PasswordSetting.Length < 3) { MessageBox.Show( (settings.UsernameSetting.Length < 3 ? "Please enter a username in the settings\r\n" : string.Empty) + (settings.PasswordSetting.Length < 3 ? "Please enter a password in the settings\r\n" : string.Empty) ); return; } LoadingBar.IsEnabled = true; LoadingBar.Visibility = Visibility.Visible; client.UploadStringAsync( new Uri(AppResources.BaseAddress + "subsite/login"), "POST", string.Format(POST_STRING, settings.UsernameSetting, settings.PasswordSetting)); } private void LoadDates() { status = 0; //Termine runningOps++; client.DownloadStringAsync(new Uri(AppResources.BaseAddress + URL_DATES)); } private void LoadResults() { status = 1; //Ergebnisse runningOps++; client.DownloadStringAsync(new Uri(AppResources.BaseAddress + URL_RESULTS)); } private void DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { runningOps--; if (runningOps == 0) { //alle Operationen sind fertig LoadingBar.IsEnabled = false; LoadingBar.Visibility = Visibility.Collapsed; btn.IsEnabled = true; } if (e.Cancelled || e.Error != null) return; //Antwort erhalten var source = e.Result.Replace("\r", "").Replace("\n", ""); switch (status) { case 0: //Termine geladen foreach (Match match in regexDates.Matches(source)) { var tb = new TextBlock(); var g = match.Groups; tb.Text = string.Format( "{1} {2} {3}{0}{4} {5}{0}{6}", Environment.NewLine, g[1].Value, g[2].Captures.Count > 0 ? g[2].Value : string.Empty, g[3].Captures.Count > 0 ? "- " + g[3].Value : string.Empty, g[5].Value, g[6].Captures.Count > 0 ? "bei " + g[6].Value : string.Empty, ( g[7].Captures.Count > 0 ? g[7].Value : string.Empty ) + ( g[8].Captures.Count > 0 ? g[8].Value != g[4].Value ? g[8].Value + " != " + g[4].Value : g[8].Value : g[4].Captures.Count > 0 ? g[4].Value : string.Empty ) ); DatesPanel.Children.Add(tb); } break; case 1: //Ergebnisse geladen foreach (Match match in regexResults.Matches(source)) { var tb = new TextBlock(); var g = match.Groups; tb.Text = string.Format( "{1} {2} {3}{0}{4} {5}{0}{6}", Environment.NewLine, g[1].Value, g[2].Captures.Count > 0 ? g[2].Value : string.Empty, g[3].Captures.Count > 0 ? "- " + g[3].Value : string.Empty, g[5].Value, g[6].Captures.Count > 0 ? "bei " + g[6].Value : string.Empty, ( g[7].Captures.Count > 0 ? g[7].Value : string.Empty ) + ( g[8].Captures.Count > 0 ? g[8].Value != g[4].Value ? g[8].Value + " != " + g[4].Value : g[8].Value : g[4].Captures.Count > 0 ? g[4].Value : string.Empty ) ); ResultsPanel.Children.Add(tb); } break; default: return; } } void UploadStringCompleted(object sender, UploadStringCompletedEventArgs e) { //Login completed LoadDates(); //THIS WOULD YIELD AN ERROR FROM THE WEBCLIENT SAYING IT ISNT SUPPORTING MULTIPLE ASYNC ACTIONS //LoadResults(); } private async void ClickOnRefresh(object sender, EventArgs e) { var isUp = await IsUp(); if (isUp) GetSite(); else MessageBox.Show("The site is down! :("); } private void ClickOnSettings(object sender, EventArgs e) { NavigationService.Navigate(new Uri("/Settings.xaml", UriKind.Relative)); } private async TaskIsUp() { btn.IsEnabled = false; const string ISUPMELINK = "http://www.isup.me/{0}"; var data = await RequestData(string.Format(ISUPMELINK, AppResources.BaseAddress.Replace("https://", string.Empty))); var isUp = !data.Contains("It's not just you!"); btn.IsEnabled = true; return isUp; } private async void ClickOnTestConnection(object sender, EventArgs e) { var isUp = await IsUp(); MessageBox.Show(string.Format("The site is {0}! :{1}", isUp ? "up" : "down", isUp ? ")" : "(")); } private static async Task RequestData(string url) { using (var httpClient = new HttpClient()) return await httpClient.GetStringAsync(new Uri(url)); } } }
\n我尝试过/我期望的/阻碍我的是:\n
- \n
- 我最初的想法是让所有操作异步进行,并在所有请求上使用await。\n所以我进行了研究,发现WebClient有一个新的async/await实现。\n
WebClient.DownloadStringTaskAsync
但是我在我的WebClient中找不到这个方法,所以我认为目前WP8.1没有实现。 - 第二个想法是使用我已经使用的HttpClient.GetStringAsync(URI)方法,该方法支持async/await。\n正如我所说,我需要一个Cookie与请求一起使用,所以我进行了研究,找到了这个。\n然而,我找不到HttpClientHandler,也没有HttpClient.CookieContainer或类似的属性。
- 我还尝试等待一个站点完成,然后再进行下一个,但是我阻塞了我的GUI线程,不想在单独的线程中编写整个事件处理程序,也不知道如何高效地实现。
\n
\n
\n