我必须编写一个异步方法来联系Web服务。这是我在WebServiceHelper类中的方法:
public static Task<int> SignIn(string username, string password)
{
try
{
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
service.LoginCompleted += (object sender, WebService.LoginCompletedEventArgs e) =>
{
if (e.Error != null) tcs.SetResult(-1);
else
tcs.SetResult((int)e.Result);
};
service.LoginAsync(username, password);
return tcs.Task;
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
return null;
}
}
然后我在按钮点击事件中调用它:
private async void btLogIn_Click(object sender, RoutedEventArgs e)
{
try
{
int si = await WebServiceHelper .SignIn(tbUsername.Text, tbPassword.Text);
if (si != 0) MessageBox.Show("Signed in successfully!");
else MessageBox.Show("Couldn't sign in");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
我第一次点击按钮时工作正常,但当我再次进入时,出现错误: “InvalidOperationException,尝试将任务转换为已完成的最终状态。”
我做了一些小搜索,并在此处找到了一些内容:Tasks seem to start automatically
我知道我应该先做一些事情来重新启动它,但我不确切知道如何以及为什么。有人可以帮我解释一下吗?
答案 0 :(得分:1)
我怀疑问题是您没有取消注册您的事件处理程序,每次调用此方法时,您都要向service.LoginCompleted
添加新的匿名事件处理程序
试试这个
public static Task<int> SignIn( string username, string password )
{
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
EventHandler<WebService.LoginCompletedEventArgs> onLoginCompleted = null;
onLoginCompleted = ( object sender, WebService.LoginCompletedEventArgs e ) =>
{
service.LoginCompleted += onLoginCompleted;
if(e.Error != null)
{
tcs.SetResult( -1 );
}
else
{
tcs.SetResult( (int)e.Result );
}
};
service.LoginCompleted += onLoginCompleted;
service.LoginAsync( username, password );
return tcs.Task;
}
或者这个
public static Task<int> SignIn( string username, string password )
{
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
EventHandler<WebService.LoginCompletedEventArgs> onLoginCompleted = ( object sender, WebService.LoginCompletedEventArgs e ) =>
{
if(e.Error != null)
{
tcs.SetResult( -1 );
}
else
{
tcs.SetResult( (int)e.Result );
}
};
service.LoginCompleted += onLoginCompleted;
tcs.Task.ContinueWith(task => service.LoginCompleted -= onLoginCompleted);
service.LoginAsync( username, password );
return tcs.Task;
}
另外,您还应该删除该方法周围的通用try/catch
,并在所有情况下返回tcs.Task
。
如果实际可能service.LoginAsync( username, password )
可能会抛出异常,那么你应该这样做
...
try
{
service.LoginAsync( username, password );
}
catch(SomeParticularException ex)
{
tcs.SetException(ex);
}
return tcs.Task;
答案 1 :(得分:1)
我尝试使用方法TrySetResult()而不是SetResult(),它有效!