我正在使用WebClient从服务器获取一些JSON数据。我希望它是同步的(是的,我知道在WP中一切都应该是异步的,但我需要从某种原因进行同步)。在我的班上,我有这样的代码:
private WebClient _webClient;
private string _acctualResponse;
private AutoResetEvent _lock = new AutoResetEvent(false);
void _webClient_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
_acctualResponse = e.Result;
_lock.Set();
}
public string _message;
public string SendString(string URL, string message)
{
_webClient.UploadStringAsync(new Uri(URL), message);
_lock.WaitOne();
return _acctualResponse;
}
在我的程序中,我正在使用它来获取一些不同的数据集。一切正常,返回数据很少。当我必须获得更大的数据(base64中的3 img)时,事件无法启动。
但!
当我删除_lock时,事件总是在SendString
函数结束后开始。我尝试使用其他一些机制等待响应,例如while
循环:
private void WaitForResponse()
{
_acctualRequestTime = 0;
_acctualResponse = null;
while (!_uploadComplet && _acctualRequestTime < Timeout)
{
int slepTime = 200;
Thread.Sleep(slepTime);
_acctualRequestTime += slepTime;
}
_uploadComplet = false;
}
[当然,事件我将_uploadComplete
标志设置为true]
效果是相同的:无论设置了什么超时间隔,响应在超时后都会短暂。
我对这种情况感到有点困惑。你知道我做得不好吗?
答案 0 :(得分:1)
我也有这个问题。
您可以使用:
public T Get<T>(string apiMethod) where T : class
{
T outputObject;
lock (syncObj)
{
downloadHandle = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback(DownloadAsync), apiMethod);
downloadHandle.WaitOne();
outputObject = JsonHelper.Parse<T>(result);
}
return outputObject;
}
protected void DownloadAsync(object _uri)
{
try
{
var url = _uri as string;
WebClient client = new WebClient();
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
client.DownloadStringAsync(new Uri(GLOBALS.MAIN_API_URL + url, UriKind.Absolute));
}
catch (Exception ex)
{
downloadHandle.Set();
}
}
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
(sender as WebClient).DownloadStringCompleted -= client_DownloadStringCompleted;
try
{
result = e.Result;
}
catch (Exception ex)
{
result = ex.Message;
}
finally
{
downloadHandle.Set();
}
}
现在你可以这样使用:
public Song GetSong(int _id)
{
var wr = Get<SongInfoWrapper>("info/song/" + _id);
if (wr != null)
{
if (wr.Error == null)
{
return wr.Element;
}
}
return null;
}
但可以肯定的是,GetSong方法在UI线程中没有调用。
答案 1 :(得分:0)
WebClient
会在UI线程上引发事件。因此,如果您正在等待UI线程并且不控制主事件循环,则事件将排队,因此永远不会传递。
由于WebClient
执行UI线程上的所有处理,Microsoft和许多其他人建议不要使用它。相反,应该使用WebRequest
。它甚至可以解决你的问题。 (虽然阻止UI线程并不是一件好事。)