ScheduledTaskyAgentにHttpWebRequestを使用する.

40216 ワード

ScheduledTaskyAgentはWP 7のバックグラウンドエージェントであり、ライブTileを更新するなど、バックグラウンドでいくつかの動作を実行することができる.プッシュ通知でLive Tileを更新することができますが、いくつかのリアルタイム性が要求されるタスクは、バックグラウンドエージェントで行うことができます.
しかし、バックグラウンドエージェントはいくつかのAPIが使えないなど、多くの制限があります.http://msdn.microsoft.com/zh-cn/library/hh202962(v=vs.92).aspx ここにはバックグラウンドエージェントがサポートしていないAPIリストがあります.カメラなどのデバイスはバックグラウンドエージェントでは使えません.注意すべきAPI:
GeoCoordinate Watch
このAPIは、装置の地理的座標を取得するために使用され、バックグラウンドエージェントで使用されることをサポートするが、リアルタイムデータではなく、キャッシュされた位置値を使用する.デバイスは15分ごとにキャッシュの位置値を更新する.
Mutex クラス
Mutexクラス同期を使用して、フロント・アプリケーションとバックグラウンド・エージェントとの間で共有されるリソース(例えば、別個の記憶中のファイル)へのアクセスを行うべきである.
Shell Toast クラス
クラスは、実行中のバックグラウンドエージェントからToast通知をポップアップするために使用されてもよい.
ShellTile クラス  Update(ShellTileData) 方法ShellTile クラス  Delete()()() 方法ShellTile クラス  Active Tiles を選択します
これらの方法は実行中のバックグラウンドエージェントにおけるshell磁気ペーストを修正するために使用できる.なお、バックグラウンドエージェントでは、shellマグネットを作成できません.
HttpWebRequest クラス
このクラスは、実行中のバックグラウンドエージェントからWeb要求を行うことができます.
 
HttpWebRequest類があれば目的を達成できます.インターネットからデータを要求し、ShellTileのUpdate()方法でLive Tileを更新すればいいです.使用中にもいくつかの問題を発見し、記録しました.
 
まずはライブTileを実現します.
http://msdn.microsoft.com/zh-cn/library/hh202979(v=vs.92).aspx どのようにLive Tileを作成し、変更するかをプレゼンテーションします.私の目的は通貨レートを表示するLive Tileを作成することです.コードは以下の通りです.
 1 /// <summary>
2 /// Handles the Click event of the menuPinToStart control.
3 /// </summary>
4 /// <param name="sender">The source of the event.</param>
5 /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
6 private void menuPinToStart_Click(object sender, RoutedEventArgs e)
7 {
8 MenuItem menuItem = sender as MenuItem;
9 CurrEntity currEntity = menuItem.DataContext as CurrEntity;
10
11 if (currEntity.CurrBase.Code != currEntity.CurrTarget.Code)
12 {
13 StringBuilder sb = new StringBuilder();
14 sb.AppendFormat(CultureInfo.InvariantCulture, paratemplate, currEntity.CurrBase.Code, currEntity.CurrTarget.Code);
15
16 // Look to see whether the Tile already exists and if so, don't try to create it again.
17 ShellTile TileToFind = ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString().Contains("MainPage.xaml?" + sb.ToString()));
18
19 // Create the Tile if we didn't find that it already exists.
20 if (TileToFind == null)
21 {
22 // Create the Tile object and set some initial properties for the Tile.
23 // The Count value of 12 shows the number 12 on the front of the Tile. Valid values are 1-99.
24 // A Count value of 0 indicates that the Count should not be displayed.
25 StandardTileData NewTileData = new StandardTileData
26 {
27 BackgroundImage = new Uri("TileBackground.png", UriKind.Relative),
28 Title = "1" + currEntity.CurrBase.Code + "=" + currEntity.Rate.ToString() + currEntity.CurrTarget.Code,
29 Count = 0,
30 BackTitle = currEntity.TradeDate.ToString(),
31 BackContent = "1" + currEntity.CurrBase.Code + " = " + currEntity.Rate.ToString() + currEntity.CurrTarget.Code,
32 //BackBackgroundImage = new Uri("Blue.jpg", UriKind.Relative)
33 };
34 // Create the Tile and pin it to Start. This will cause a navigation to Start and a deactivation of our application.
35 ShellTile.Create(new Uri("/MainPage.xaml?" + sb.ToString(), UriKind.Relative), NewTileData);
36 }
37 }
38 }
各通貨を区別するために、ShellTileのNavigationUri属性に通貨コードを添付します.これはバックグラウンドエージェントから該当する通貨を取り出すことができます.
 
バックグラウンドエージェントを作成します.新しいバックグラウンドエージェントを作成します.
http://msdn.microsoft.com/zh-cn/library/hh202941(v=vs.92).aspx このページでは、バックグラウンドエージェントを使ってToast通知をポップアップする方法をデモンストレーションしています.Live Tileを更新するためには、変更が必要です.キーコードは以下の通りです.
 1 protected override void OnInvoke(ScheduledTask task)
2 {
3 //TODO: Add code to perform your task in background
4 string toastMessage = "";
5
6 // If your application uses both PeriodicTask and ResourceIntensiveTask
7 // you can branch your application code here. Otherwise, you don't need to.
8 if (task is PeriodicTask)
9 {
10 // Execute periodic task actions here.
11 toastMessage = "Periodic task running.";
12 }
13 else
14 {
15 // Execute resource-intensive task actions here.
16 toastMessage = "Resource-intensive task running.";
17 }
18
19 // Launch a toast to show that the agent is running.
20 // The toast will not be shown if the foreground application is running.
21 ShellToast toast = new ShellToast();
22 toast.Title = "Background Agent Sample";
23 toast.Content = toastMessage;
24 toast.Show();
25
26 // If debugging is enabled, launch the agent again in one minute.
27 #if DEBUG_AGENT
28 ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(60));
29 #endif
30
31 // Call NotifyComplete to let the system know the agent is done working.
32 NotifyComplete();
33 }
そのコードをLive Tileのコードに変更すればいいです.まず非同期でデータを要求し、ライブTileを更新します.非同期要求のコードは以下の通りです.
  1 /// <summary>
2 /// State information for our BeginGetResponse async call
3 /// </summary>
4 public class RequestState
5 {
6 public HttpWebRequest AsyncRequest { get; set; }
7 public HttpWebResponse AsyncResponse { get; set; }
8 }
9
10
11 private void ConvertCurrencyByHttpWebRequest()
12 {
13 //
14 bool networkIsAvailable = Microsoft.Phone.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();//
15 if (networkIsAvailable)
16 {
17 // uri
18 StringBuilder sb = new StringBuilder();
19
20 foreach (CurrEntity data in this.currEntityList)
21 {
22 try
23 {
24 //do something
37 }
38 catch
39 {
40 }
41 }
42
43 string url = String.Format(CultureInfo.InvariantCulture, currUrl, sb.ToString());
44 Uri uri = new Uri(url);
45
46 //
47 HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(uri);
48 //
49 RequestState requestState = new RequestState();
50 requestState.AsyncRequest = myRequest;
51 // Internet 。
52 //IAsyncResult result = (IAsyncResult)req.BeginGetResponse(new AsyncCallback(ResponseCallback), req);//
53 myRequest.BeginGetResponse(new AsyncCallback(ResponseCallback), requestState);
54
55
56 }
57 }
58
59
60
61 private void ResponseCallback(IAsyncResult asyncResult)
62 {
63 RequestState requestState = (RequestState)asyncResult.AsyncState;
64 //
65 HttpWebRequest myRequest = (HttpWebRequest)requestState.AsyncRequest;
66 // Internet
67 requestState.AsyncResponse = (HttpWebResponse)myRequest.EndGetResponse(asyncResult);
68 //WebResponse response = request.EndGetResponse(result);
69
70 using (Stream stream = requestState.AsyncResponse.GetResponseStream())
71 using (StreamReader respReader = new StreamReader(stream))
72 {
73 try
74 {
75 //do something
128 // Live Tile
129 UpdateTile();
130 }
131 finally
132 {
133 respReader.Close();
134 }
135
136 }
137
138 }
更新ライブTile:
 1 /// <summary>
2 /// Updates the tile. LiveTile
3 /// </summary>
4 private void UpdateTile()
5 {
6 //throw new NotImplementedException();
7 foreach (CurrEntity currEntity in currEntityList)
8 {
9 StringBuilder sb = new StringBuilder();
10 sb.AppendFormat(CultureInfo.InvariantCulture, paratemplate, currEntity.CurrBase.Code, currEntity.CurrTarget.Code);
11 // Tile
12 ShellTile TileToFind = ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString().Contains("MainPage.xaml?" + sb.ToString()));
13 if (TileToFind != null)
14 {
15 StandardTileData NewTileData = new StandardTileData
16 {
17 BackgroundImage = new Uri("TileBackground.png", UriKind.Relative),
18 Title = "1" + currEntity.CurrBase.Code + "=" + currEntity.Rate.ToString() + currEntity.CurrTarget.Code,
19 Count = 0,
20 BackTitle = currEntity.TradeDate.ToString(),
21 BackContent = "1" + currEntity.CurrBase.Code + " = " + currEntity.Rate.ToString() + currEntity.CurrTarget.Code,
22 //BackBackgroundImage = new Uri("Blue.jpg", UriKind.Relative)
23 };
24 TileToFind.Update(NewTileData);
25
26 }
27 }
28 //ShellToast toast = new ShellToast();
29 //toast.Title = "test";
30 //toast.Content = "update success!";
31 //toast.Show();
32 }
バックグラウンドエージェントのコードを:
 1 protected override void OnInvoke(ScheduledTask task)
2 {
3 //TODO: Add code to perform your task in background
4 //string toastTitle = "Periodic";
5 this.AdjustToLocalTime = true;
6 this.currEntityList = new List<CurrEntity>();
7 // If your application uses both PeriodicTask and ResourceIntensiveTask
8 // you can branch your application code here. Otherwise, you don't need to.
9 //if (task is PeriodicTask)
10 //{
11 //// Execute periodic task actions here.
12 // toastTitle = "Periodic ";
13 //}
14 //else
15 //{
16 //// Execute resource-intensive task actions here.
17 // toastTitle = "Resource-intensive ";
18 //}
19
20
21 var query = from x in ShellTile.ActiveTiles where x.NavigationUri.ToString().Contains("?s=") select x;
22 List<ShellTile> shellTileList = query.ToList();
23 if (shellTileList.Count > 0)
24 {
25 //foreach (ShellTile tile in query.ToList())
26 for (int i = 0; i < shellTileList.Count; i++)
27 {
28 ShellTile tile = shellTileList[i] as ShellTile;
29 string strCode = tile.NavigationUri.ToString().Substring(tile.NavigationUri.ToString().IndexOf("=") + 1, 6);
30 CurrEntity currEntity = new CurrEntity();
31 currEntity.CurrBase = new CurrDescEntity(strCode.Substring(0, 3), "");
32 currEntity.CurrTarget = new CurrDescEntity(strCode.Substring(3, 3), "");
33 currEntity.CurrencyAmount = 0;
34 currEntity.IsInversion = false;
35 currEntity.IsStandard = false;
36 currEntity.Rate = 0;
37 currEntity.TradeDate = System.DateTime.Now;
38 currEntityList.Add(currEntity);
39 }
40 // HttpWebRequest
41 this.ConvertCurrencyByHttpWebRequest();
42 }
43
44
45
46 // If debugging is enabled, launch the agent again in one minute.
47 #if DEBUG_AGENT
48 ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(60));
49 #endif
50
51 NotifyComplete();
52 }
Live TileのNavigationUriからパラメータを読み出し、HttpWebRequestを呼び出して非同期要求を行います.
そして運行してみます.不思議なことに、いつも更新できません.ブレークポイントデバッグ、非同期要求を発見しました. myRequest.BeginnGet Resonse(new AsyncCallback(ReponseCallback)、request State)実行しましたが、リターンデータはなかなか取得できません.ResonseCallbackはまったく実行されていないようです.
 
バックグラウンドエージェントのOnInvoke方法を見てみると、非同期要求を呼び出した後、NotifyComprate()という文が実行されていることが分かりました.
この方法は、オペレーティングシステムに通知し、プロキシは現在のプロキシに対して呼び出した所定のタスクを完了しました.
すなわち、非同期要求を開始した後、非同期の結果が返ってくるまで、システムエージェントに任務が完了したことを通知し、ReponseCallbackが実行されていないことを招いた.
したがって、NotifyComplettee()を非同期のデータに転送したら良いです.202.20追加:http://forums.create.msdn.com/forums/p/90294/587823.aspx#587823
次のように書くことができます.
Move NotifyComplete() into your anonymous delegate like this:
1 protected override void OnInvoke(ScheduledTask task)
2 {
3 // tried also Create instead of CreateHttp
4 var request = (HttpWebRequest)HttpWebRequest.CreateHttp(new Uri("http://www.1112.net/lastpage.html"));
5
6
7 // breakpoint here #1
8 request.BeginGetResponse((ar) =>
9 {
10 // breakpoint here #2
11 try
12 {
13 using (StreamReader reader = new StreamReader(request.EndGetRequestStream(ar)))
14 {
15 // breakpoint here #3
16 string result = reader.ReadToEnd();
17 }
18 }
19 catch (Exception)
20 {
21 // breakpoint here #4
22 }
23 // call it here.
24 NotifyComplete();
25 }, null);
26
27 // DON'T call this here.
28 // NotifyComple