我正在尝试编写一个使用Task和TaskCompletion的函数。
我的问题是登录后,结果不会返回。之前我使用过类似的代码,它正在运行。我不知道造成这种情况的原因。
public async Task<byte[]> Sign(byte[] documentContent)
{
var service = new SignServiceWrapper("https://example.com?wsdl");
var loginResult = await Task.Run(() => service.Login(loginRequest));
//....
}
和我的SignServiceWrapper类
public class SignServiceWrapper
{
private static string _webServiceUrl;
private BrokerClientClient client;
public SignServiceWrapper(string webServiceUrl)
{
_webServiceUrl = webServiceUrl;
}
public Task<loginResponse> Login(loginRequest request)
{
var tcs = new TaskCompletionSource<loginResponse>();
ClientGenerator.WebServiceUrl = _webServiceUrl;
ClientGenerator.InitializeService();
client = ClientGenerator.ServiceClient;
client.loginCompleted += (sender, loginResult) =>
{
if (loginResult.Error != null)
tcs.SetException(loginResult.Error);
else
tcs.TrySetResult(loginResult.Result);
};
client.loginAsync(request);
return tcs.Task;
}
// ...
}
如果我这样调用我的登录功能
var loginResult = Task.Run(() => service.Login(loginRequest));
loginResult.Wait();
我知道有一种僵局,但我不知道如何在这里解决这个问题以及对象。
答案 0 :(得分:2)
这是一个有效的.NET Fiddle。
我认为你的.Login
方法试图做得太多。我注意到的第一件事(并且只能想象它是如何实现的)是静态ClientGenerator
,它具有静态可变状态。这是令人震惊的,非常具体的代码味道。我希望看到客户端本身的样子以及如何实现,因为这肯定有助于更好地回答这个问题。
根据您目前所分享的内容(并假设client.loginAsync
返回Task<loginResponse>
),我会说您可以执行以下操作:
public class SignServiceWrapper
{
private static string _webServiceUrl;
private BrokerClientClient client;
public SignServiceWrapper(string webServiceUrl)
{
_webServiceUrl = webServiceUrl;
}
public Task<loginResponse> LoginAsync(loginRequest request)
{
ClientGenerator.WebServiceUrl = _webServiceUrl;
ClientGenerator.InitializeService();
client = ClientGenerator.ServiceClient;
return client.loginAsync(request);
}
// ...
}
然后你可以这样消费:
public async Task<byte[]> Sign(byte[] documentContent)
{
var service = new SignServiceWrapper("https://example.com?wsdl");
var loginResult = await service.LoginAsync(loginRequest);
//...
}
如果client.loginAsync
没有返回您要查找的内容,那么您需要执行此操作something similar to your current approach。或者,如果您被锁定在event-based async pattern,则还有其他注意事项 - 例如您是否要支持取消,IsBusy
,进度,增量结果以及是否有能力使用事件参数继承System.ComponentModel.AsyncCompletedEventArgs
等......
最后一个考虑因素,如果client.loginAsync
返回Task
,即使它没有返回loginResponse
,您也需要等待它:
public async Task<loginResponse> Login(loginRequest request)
{
var tcs = new TaskCompletionSource<loginResponse>();
ClientGenerator.WebServiceUrl = _webServiceUrl;
ClientGenerator.InitializeService();
client = ClientGenerator.ServiceClient;
client.loginCompleted += (sender, loginResult) =>
{
if (loginResult.Error != null)
tcs.SetException(loginResult.Error);
else
tcs.TrySetResult(loginResult.Result);
};
await client.loginAsync(request);
return tcs.Task;
}
<强>更新强>
与OP讨论后,这.NET Fiddle似乎符合他的需要。
答案 1 :(得分:-1)
更改var loginResult = await Task.Run(() =>service.Login(loginRequest));
至var loginResult = await service.Login(loginRequest);