1、说明
在实际的使用过程中,都会存在第三方的API的情况,但第三方API可能存在网络及本身的异常,造成UI阻塞。本篇主要解决异步调用API且不阻塞UI的相关知识。
2、具体实现
2.1 前提说明
1、开发环境:VS2019、.NET Framework4.5、win10企业版
2、webapi
先创建了一个webapi,内容非常简单
public class ZLController : ApiController
{
public string getZL()
{
var temp = new { id = "123", name = "郑林" };
Thread.Sleep(5000);
return JsonConvert.SerializeObject(temp);
}
}
4、效果如下
2.1 使用HttpClient
1、HttpClient
是在.NET Framework4.5中增加的。因此需要注意本地.NET Framework
的版本。
2、HttpClient
类中的方法均为异步。
3、效果如下如下:
4、代码如下:
private async void asyncButtonClick(object sender, EventArgs e)
{
try
{
string resultStr = await httpClient.GetStringAsync("http://localhost/SomeApiDemo/api/zl/getzl");
this.label1.Text = resultStr;
}
catch (Exception ex)
{
if (ex is System.Threading.Tasks.TaskCanceledException)
{
MessageBox.Show("通信接口延迟timeOut后,仍无回复");
}
else
{
MessageBox.Show(ex.Message);
}
}
}
2.2 使用WebRequest
WebRequest是从.NET Framework1.0
就有了。
1、效果
2、代码
private void button5_Click(object sender, EventArgs e)
{
//写法1
Task<string> testtask = new Task<string>(syncWebRequest);//具体执行方法
testtask.ContinueWith(myaction, m_syncContextTaskScheduler);//成功后的回调方法
testtask.Start();
}
syncWebRequest方法的内容:
//调用API,并进行返回的方法--供方法2和方法3使用
private string syncWebRequest()
{
string getdata = "";
try {
WebRequest request = WebRequest.Create("http://localhost/SomeApiDemo/api/zl/getzl");
request.Timeout = 10000;
//请求,并获取数据
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
getdata = reader.ReadToEnd();
reader.Close();
dataStream.Close();
response.Close();
}catch(Exception ex)
{
if(ex.Message=="操作超时")
{
getdata = "通信接口延迟timeOut后,仍无回复";
}
else
{
getdata = ex.Message;
}
}
return getdata;
}
myaction的回调方法
//成功之后的回调方法
private void myaction(Task<string> mytask)
{
this.label4.Text = mytask.Result;
}
3、代码下载
4、其他
在网上看到另外一个可以结束Task的方法,很好玩。
namespace Walterlv
{
public static class TaskWaitingExtensions
{
public static async Task<TResult> WaitAsync<TResult>(this Task<TResult> task, TimeSpan timeout)
{
using (var timeoutCancellationTokenSource = new CancellationTokenSource())
{
var delayTask = Task.Delay(timeout, timeoutCancellationTokenSource.Token);
if (await Task.WhenAny(task, delayTask) == task)
{
timeoutCancellationTokenSource.Cancel();
return await task;
}
throw new TimeoutException("The operation has timed out.");
}
}
}
}
这个是异步设置timeout的方法,最关键的使用了两个方法:Task.Delay
和Task.WhenAny
。非常巧妙的实现了定时的功能。本质上直接干翻task,根本不关心task承载的内容。刚才提到的连接在这儿。