我有一个有趣的问题..我有一个可以运行WCF服务的登录方法。
我创建了一个任务完成并等待结果到来。
问题是,如果我调用2次登录方法,第二次不返回任何内容。我把断点和它进入已完成的事件并调用trysetresult但没有任何返回。
这是我的代码
public Task<User> LoginByUserName(string userName, string password)
{
var tcs = new TaskCompletionSource<User>();
if (!_registeredEventList.Contains ("LoginByUserNameCompleted")) {
_registeredEventList.Add ("LoginByUserNameCompleted");
userService.LoginByUserNameCompleted += (object sender, LoginByUserNameCompletedEventArgs args) => {
if (args.Error != null)
tcs.TrySetException (args.Error);
if (args.Result != null)
tcs.TrySetResult (args.Result);
else
tcs.TrySetResult (null);
};
}
userService.LoginByUserNameAsync (userName,password);
return tcs.Task;
}
我这样打电话;
var loginResult= await Task.Run(()=>serviceHelper.LoginByUserName(userName,password));
例如,如果用户一次输入错误的登录信息,则在第二次尝试时,不会返回任何内容。
PS:如果事件已经订阅,则_registeredEventList成立。如果是,那么它不再创造。当我删除那部分时,它可以工作。
答案 0 :(得分:1)
正如Evk评论的那样,问题是你的代码有一个条件,它永远不会返回完成的任务。具体来说,第一次调用此代码时,它会向_registeredEventList
添加一个条目(可能永远不会被删除)。以后的所有调用都将返回一个永不完成的Task
,which is a major no-no in asynchronous programming。
要解决此问题,我建议您通过取消订阅作为回调的一部分来修改您的EAP包装:
public static Task<User> LoginByUserNameTaskAsync(this UserService @this, string userName, string password)
{
var tcs = new TaskCompletionSource<User>();
LoginByUserNameCompletedDelegate callback = null;
callback = (object sender, LoginByUserNameCompletedEventArgs args) =>
{
@this.LoginByUserNameCompleted -= callback;
if (args.Error != null)
tcs.TrySetException(args.Error);
else
tcs.TrySetResult(args.Result);
};
@this.LoginByUserNameCompleted += callback;
@this.LoginByUserNameAsync(userName, password);
return tcs.Task;
}
(我也把它作为一种扩展方法,让它follow the TAP naming parameters for TAP-over-EAP wrappers)。
答案 1 :(得分:-1)
我刚刚解决了同样的问题。对我来说,它不是继承 IDisposable 并添加以下内容
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed && disposing)
{
_channel?.Dispose();
_connection?.Dispose();
}
this.disposed = true;
}