我正在寻找有关WPF中Task
的一些建议,并且想知道是否有人可以查看我的代码并指出我在做错什么?
基本上,该应用程序从UI中获取用于实例化Task
服务的邮政编码,该服务将获得经度/纬度,可通过实例访问该经度以用于其他服务或UI本身。
我认为我可能想解决一种竞态条件,因为当ResultTextBlock.Text
设置为零时,但逐步进行实例化时我看到那些值已设置。
对于Task
实施和接线的任何建议,将不胜感激。
class PostcodeService
{
string _result;
string _postcode;
HttpResponseMessage _response;
RootObject rootObject;
public double Latitude { get; private set; }
public double Longitude { get; private set; }
public PostcodeService(string postcode)
{
this._postcode = postcode;
rootObject = new RootObject();
}
public async Task<string> GetLongLatAsync()
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("https://api.postcodes.io/postcodes/" + this._postcode);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
try
{
_response = await client.GetAsync(client.BaseAddress);
if(_response.IsSuccessStatusCode)
{
//cast result into model and then set long/lat properties which can then be used in the UI
_result = await _response.Content.ReadAsStringAsync();
rootObject = JsonConvert.DeserializeObject<RootObject>(_result);
Longitude = Double.Parse(rootObject.result.longitude.ToString());
Latitude = Double.Parse(rootObject.result.latitude.ToString());
}
}
catch(Exception ex)
{
ex.ToString();
}
}
TaskCompletionSource<string> tc = new TaskCompletionSource<string>(_result);
return tc.ToString();
}
}
private void PostcodeButton_Click(object sender, RoutedEventArgs e)
{
_clearStatus();
if (_validatePostcode())
{
Task T1 = Task.Factory.StartNew(async () =>
{
// get long lat from api
_postcode = new PostcodeService(PostcodeTextBox.Text);
await _postcode.GetLongLatAsync();
});
//Race condition?
ResultTextBlock.Text = _postcode.Latitude.ToString();
}
}
答案 0 :(得分:2)
事件处理程序允许使用异步void
引用Async/Await - Best Practices in Asynchronous Programming
private async void PostcodeButton_Click(object sender, RoutedEventArgs e) {
_clearStatus();
if (_validatePostcode()) {
// get long lat from api
_postcode = new PostcodeService(PostcodeTextBox.Text);
await _postcode.GetLongLatAsync(); //Offload UI thread
//Back on UI thread
ResultTextBlock.Text = _postcode.Latitude.ToString();
}
}
第二个为避免线程耗尽,请创建一个HttpClient
而不是在需要执行此操作时创建并处理它
引用You're using HttpClient wrong
服务的设计应重构为单独的关注点
public class Location {
public Location(double lat, double lon) {
Latitude = lat;
Longitude = lon;
}
public double Latitude { get; private set; }
public double Longitude { get; private set; }
}
public class PostcodeService {
private static Lazy<HttpClient> client;
static PostcodeService() {
client = new Lazy<HttpClient>(() => {
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("https://api.postcodes.io/postcodes/");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
return httpClient;
});
}
public async Task<Location> GetLongLatAsync(string postcode) {}
var response = await client.Value.GetAsync(postcode);
if(response.IsSuccessStatusCode) {
//cast result into model and then set long/lat properties which can then be used in the UI
var rootObject = await response.Content.ReadAsAsync<RootObject>();
var Longitude = Double.Parse(rootObject.result.longitude.ToString());
var Latitude = Double.Parse(rootObject.result.latitude.ToString());
var result = new Location(Latitude, Longitude);
return result;
}
return null;
}
}
现在可以将事件处理程序重构为
private async void PostcodeButton_Click(object sender, RoutedEventArgs e) {
_clearStatus();
if (_validatePostcode()) {
// get long lat from api
var service = new PostcodeService();
var location = await service.GetLongLatAsync(PostcodeTextBox.Text); //Offload UI thread
//Back on UI thread
if(location != null) {
ResultTextBlock.Text = location.Latitude.ToString();
} else {
//Some message here
}
}
}
答案 1 :(得分:2)
您的GetLongLatAsync()
方法应返回string
:
public async Task<string> GetLongLatAsync()
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("https://api.postcodes.io/postcodes/" + this._postcode);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
_response = await client.GetAsync(client.BaseAddress);
string result = null;
if (_response.IsSuccessStatusCode)
{
//cast result into model and then set long/lat properties which can then be used in the UI
result = await _response.Content.ReadAsStringAsync();
rootObject = JsonConvert.DeserializeObject<RootObject>(_result);
Longitude = Double.Parse(rootObject.result.longitude.ToString());
Latitude = Double.Parse(rootObject.result.latitude.ToString());
}
return result;
}
}
...,您只需在用户界面中等待GetLongLatAsync()
:
private async void PostcodeButton_Click(object sender, RoutedEventArgs e)
{
_clearStatus();
if (_validatePostcode())
{
// get long lat from api
_postcode = new PostcodeService(PostcodeTextBox.Text);
string result = await _postcode.GetLongLatAsync();
ResultTextBlock.Text = result.ToString();
}
}
您无需使用TaskCompletionSource
或启动新的Task
来调用异步方法。