Để trả lời phần thứ hai trước, bạn cần đánh dấu sự kiện cho nút async
, nếu bạn muốn sử dụng từ khóa await
trong mã của mình, bạn phải khai báo hàm async
.
Thứ hai nếu hàm sử dụng async
mà không cần await
bên trong mã sẽ không chạy không đồng bộ, bạn cần phải tạo công việc và chạy phương thức đồng bộ bên trong hoặc viết lại phương thức không đồng bộ.
Là phương pháp nhiệm vụ:
private async void button1_Click(object sender, EventArgs e)
{
txtLog.AppendText("Before Await");
//Note I changed from "Task<bool>" to "bool", await is like calling ".Result"
// on a task but not blocking the UI, so you store the type you are waiting for.
bool result = await Task.Run(() => login("","")); //You would still use your old login code before you tried to make it async, it requires no modifications.
txtLog.AppendText("After Await");
txtLog.AppendText("Result: " + result.ToString());
}
Viết lại phương pháp chức năng:
private async void button1_Click(object sender, EventArgs e)
{
txtLog.AppendText("Before Await");
//Note I changed from "Task<bool>" to "bool", await is like calling ".Result"
// on a task but not blocking the UI, so you store the type you are waiting for.
bool result = await login("","");
txtLog.AppendText("After Await");
txtLog.AppendText("Result: " + result.ToString());
}
private Task<bool> login(String username, String password)
{
var tcs = new TaskCompletionSource<bool>();
// Make the login request
var request = new RestSharp.RestRequest("/accounts/login/", RestSharp.Method.POST);
request.AddParameter("username", username);
request.AddParameter("password", password);
client.ExecuteAsync(request, (response, handle) =>
{
try
{
// Return loggin status
var dom = response.Content;
//dom["html"] did not have a .HasClass in my tests, so this code may need work.
tcs.TrySetResult(dom["html"].HasClass("logged-in"));
}
catch(Exception ex)
{
tcs.TrySetException(ex);
}
});
return tcs.Task;
}
Trong "Phương pháp viết lại" của tôi những gì tôi đang làm là tôi đang sử dụng ExecuteAsync
phù thủy là part of IRestClient. Hàm đó gọi phương thức gọi lại khi nó hoàn thành, trong phương thức gọi lại, tôi gọi's SetResult
để báo cáo lại kết quả mà tôi muốn.
Bạn có thể mở rộng này hơn nữa bằng cách tham gia trong một CancellationToken
và nếu token được nâng lên gọi Abort()
trên RestRequestAsyncHandle
, tuy nhiên nếu chúng ta làm được điều này chúng ta cần phải đưa async
lại vào chức năng và chờ đợi kết quả vì vậy chúng tôi có thể dọn dẹp sau khi đăng ký mã thông báo hủy.
private Task<bool> login(String username, String password)
{
return login(username, password, CancellationToken.None);
}
private async Task<bool> login(String username, String password, CancellationToken cancelToken)
{
var tcs = new TaskCompletionSource<bool>();
// Make the login request
var request = new RestSharp.RestRequest("/accounts/login/", RestSharp.Method.POST);
request.AddParameter("username", username);
request.AddParameter("password", password);
var asyncHandle = client.ExecuteAsync(request, (response, handle) =>
{
try
{
// Return loggin status
var dom = response.Content;
tcs.TrySetResult(dom["html"].HasClass("logged-in"));
}
catch(Exception ex)
{
tcs.TrySetException(ex);
}
});
//if the token is canceled it will call `asyncHandle.Abort()` for us.
using(cancelToken.Register(() =>
{
if(tcs.TrySetCanceled(cancelToken))
asyncHandle.Abort();
}))
{
return await tcs.Task;
}
}
Scott bạn vừa trả lời hai câu hỏi trong một cho tôi vì tôi chỉ tìm cách sử dụng ExecuteAsync và đang bối rối về cách sử dụng nó. Ngoài ra, tôi đã sử dụng CsQuery có phương pháp "HasClass". –
Tôi đã thực hiện một vài chỉnh sửa trên phiên bản có thể hủy, bạn cần phải thông báo 'tcs' rằng công việc đã bị hủy.Tôi cũng thêm hỗ trợ cho nó báo cáo bất kỳ trường hợp ngoại lệ có thể được ném vào cuộc gọi lại. –
Câu trả lời này hữu ích cho tôi. Cảm ơn bạn. –