2012-07-11 18 views
6

Webclient'ten Json'a yanıtı dönüştürmeye çalışıyorum, ancak sunucudan indirilmeden önce JSON nesnesini oluşturmaya çalışıyor. WebOpenReadCompleted'in yürütülmesini beklemem için "güzel" bir yol var mı?Etkinliğin bitmesi bekleniyor

bu bir WP7 uygulaması olduğunu söz var, yani her şey Sen zaman uyumsuz okuma tamamlanana kadar bir EventWaitHandle güzel engellemek için kullanabileceğiniz zaman uyumsuz

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(); 
      }  
     } 
    } 
} 

cevap

2

olduğunu. WebClient ile dosya indirmek için benzer bir gereksinimi vardı. Benim çözümüm WebClient alt sınıfını kullanmaktı. Tam kaynak aşağıda. Özellikle, async indirme işlemi tamamlanana kadar DownloadFileWithEvents güzel bir şekilde bloklar. Sınıfı amacınıza göre değiştirmek oldukça kolay olmalıdır.

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, burada kullanılacak doğru şey gibi görünüyor. – nickknissen

2

OpenReadAsync() kullandığınızı görüyorum. Bu, eşzamanlı bir yöntemdir, yani işleyici iş parçacığı yürütülürken arama iş parçacığı askıya alınmaz.

Bu, WebOpenReadCompleted() hala yürütülürken, atama işlemi ayarı jsonsobject'iniz anlamına gelir.

En iyi seçeneğinizin, OpenReadAsync (yeni Uri (url)) ile Open (uri (url)) yönteminizi Connect (string url) yönteminizle değiştireceğini söyleyebilirim.

OpenRead() bir senkronizasyon işlemidir, bu nedenle çağrı yöntemi, bağlantınız Connect() yönteminde gerçekleşmeden önce WebOpenReadCompleted() yöntemi tamamlanana kadar bekler.

+0

Bu bir WP7 uygulaması olduğundan, webclient için senkronize işlem olmadığından bahsetmiştim, bu konuda üzgünüm – nickknissen

+0

Yeterince adil ... Öyleyse, evet, EventWaitHandle kullanımını gösteren diğer mesaj yolun – d3v1lman1337

İlgili konular