Waiting for the completion of the event

I am trying to convert a response from webclient to Json, but it is trying to create a JSON object before it will dump it from the server. Is there a “good” way for me to wait for WebOpenReadCompleted to complete?

It should be mentioned that this is a WP7 application, so all this is Async

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(); } } } } 
+6
source share
2 answers

You can use EventWaitHandle to lock nicely until async reading is complete. I had a similar requirement for uploading files using WebClient . My solution was to subclass WebClient . The full source is given below. In particular, DownloadFileWithEvents blocks nicely until the async download completes.

For your purpose, it is quite simple to change the class.

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

I see that you are using OpenReadAsync (). This is an asynchronous method, meaning that the calling thread does not pause during the execution of the handler.

This means that the jsonsobject parameter of the assignment operation is executed while WebOpenReadCompleted () is being executed.

I would say that it is best to replace OpenReadAsync (new Uri (url)) with OpenRead (new Uri (url)) in your Connect (string url) method.

OpenRead () is a synchronous operation, so the calling method will wait for the WebOpenReadCompleted () method to complete before your assignment happens in the Connect () method.

+2
source

Source: https://habr.com/ru/post/920253/


All Articles