2012-07-11 14 views
6

WebクライアントからJsonに応答を変換しようとしていますが、JSONオブジェクトをサーバーからダウンロードする前にJSONオブジェクトを作成しようとしています。 WebOpenReadCompletedが実行されるのを待つための「素敵な」方法はありますか?イベントが終了するのを待って

が、これはWP7アプリであることを言及する必要があり、そのすべてがあなたが非同期読み込みが完了するまでEventWaitHandleがうまくブロックするために使用できる非同期

public class Client 
{ 

    public String _url; 
    private String _response; 
    private WebClient _web; 

    private JObject jsonsobject; 
    private Boolean blockingCall; 


    private Client(String url) 
    { 
     _web = new WebClient(); 
     _url = url; 
    } 

    public JObject Login(String username, String password) 
    { 
     String uriUsername = HttpUtility.UrlEncode(username); 
     String uriPassword = HttpUtility.UrlEncode(password); 

     Connect(_url + "/data.php?req=Login&username=" + uriUsername + "&password=" + uriPassword + ""); 
     jsonsobject = new JObject(_response); 
     return jsonsobject; 
    } 

    public JObject GetUserInfo() 
    { 

     Connect(_url + "/data.php?req=GetUserInfo"); 
     jsonsobject = new JObject(_response); 
     return jsonsobject; 
    } 

    public JObject Logout() 
    { 

     Connect(_url + "/data.php?req=Logout"); 
     jsonsobject = new JObject(_response); 
     return jsonsobject; 
    } 

    private void Connect(String url) 
    { 

     _web.Headers["Accept"] = "application/json"; 
     _web.OpenReadCompleted += new OpenReadCompletedEventHandler(WebOpenReadCompleted); 
     _web.OpenReadAsync(new Uri(url)); 
    } 

    private void WebOpenReadCompleted(object sender, OpenReadCompletedEventArgs e) 
    { 
     if (e.Error != null || e.Cancelled) 
     { 
      MessageBox.Show("Error:" + e.Error.Message); 
      _response = ""; 
     } 
     else 
     { 
      using (var reader = new StreamReader(e.Result)) 
      { 
       _response = reader.ReadToEnd(); 
      }  
     } 
    } 
} 

答えて

2

です。私はWebClientでファイルをダウンロードする同様の要件がありました。私の解決策はサブクラスWebClientでした。完全なソースは以下です。具体的には、DownloadFileWithEventsは非同期ダウンロードが完了するまでうまくブロックされます。

目的に合わせてクラスを変更するのは簡単です。

public class MyWebClient : WebClient, IDisposable 
{ 
    public int Timeout { get; set; } 
    public int TimeUntilFirstByte { get; set; } 
    public int TimeBetweenProgressChanges { get; set; } 

    public long PreviousBytesReceived { get; private set; } 
    public long BytesNotNotified { get; private set; } 

    public string Error { get; private set; } 
    public bool HasError { get { return Error != null; } } 

    private bool firstByteReceived = false; 
    private bool success = true; 
    private bool cancelDueToError = false; 

    private EventWaitHandle asyncWait = new ManualResetEvent(false); 
    private Timer abortTimer = null; 

    const long ONE_MB = 1024 * 1024; 

    public delegate void PerMbHandler(long totalMb); 

    public event PerMbHandler NotifyMegabyteIncrement; 

    public MyWebClient(int timeout = 60000, int timeUntilFirstByte = 30000, int timeBetweenProgressChanges = 15000) 
    { 
     this.Timeout = timeout; 
     this.TimeUntilFirstByte = timeUntilFirstByte; 
     this.TimeBetweenProgressChanges = timeBetweenProgressChanges; 

     this.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(MyWebClient_DownloadFileCompleted); 
     this.DownloadProgressChanged += new DownloadProgressChangedEventHandler(MyWebClient_DownloadProgressChanged); 

     abortTimer = new Timer(AbortDownload, null, TimeUntilFirstByte, System.Threading.Timeout.Infinite); 
    } 

    protected void OnNotifyMegabyteIncrement(long totalMb) 
    { 
     if (NotifyMegabyteIncrement != null) NotifyMegabyteIncrement(totalMb); 
    } 

    void AbortDownload(object state) 
    { 
     cancelDueToError = true; 
     this.CancelAsync(); 
     success = false; 
     Error = firstByteReceived ? "Download aborted due to >" + TimeBetweenProgressChanges + "ms between progress change updates." : "No data was received in " + TimeUntilFirstByte + "ms"; 
     asyncWait.Set(); 
    } 

    void MyWebClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) 
    { 
     if (cancelDueToError) return; 

     long additionalBytesReceived = e.BytesReceived - PreviousBytesReceived; 
     PreviousBytesReceived = e.BytesReceived; 
     BytesNotNotified += additionalBytesReceived; 

     if (BytesNotNotified > ONE_MB) 
     { 
      OnNotifyMegabyteIncrement(e.BytesReceived); 
      BytesNotNotified = 0; 
     } 
     firstByteReceived = true; 
     abortTimer.Change(TimeBetweenProgressChanges, System.Threading.Timeout.Infinite); 
    } 

    public bool DownloadFileWithEvents(string url, string outputPath) 
    { 
     asyncWait.Reset(); 
     Uri uri = new Uri(url); 
     this.DownloadFileAsync(uri, outputPath); 
     asyncWait.WaitOne(); 

     return success; 
    } 

    void MyWebClient_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) 
    { 
     if (cancelDueToError) return; 
     asyncWait.Set(); 
    } 

    protected override WebRequest GetWebRequest(Uri address) 
    {    
     var result = base.GetWebRequest(address); 
     result.Timeout = this.Timeout; 
     return result; 
    } 

    void IDisposable.Dispose() 
    { 
     if (asyncWait != null) asyncWait.Dispose(); 
     if (abortTimer != null) abortTimer.Dispose(); 

     base.Dispose(); 
    } 
} 
+0

EventWaitHandleはここで使用するのに適しています。 – nickknissen

2

あなたはOpenReadAsync()を使用しています。これは非同期メソッドです。つまり、ハンドラーの実行中に呼び出しスレッドが中断されていないことを意味します。

これは、WebOpenReadCompleted()の実行中に割り当て操作設定jsonsobjectが発生することを意味します。

あなたの最善の策は、OpenReadAsync(新しいUri(url))をConnect(string url)メソッドのOpenRead(新しいUri(url))に置き換えることです。

OpenRead()は同期操作なので、Connect()メソッドで代入が行われる前にWebOpenReadCompleted()メソッドが完了するまで呼び出しメソッドが待機します。

+0

WP7アプリだと忘れてしまったので、webclientの同期操作はありません。ごめんなさい。 – nickknissen

+0

十分に公正...それでは、EventWaitHandleを使用している他の投稿は道のりです – d3v1lman1337

関連する問題