简体   繁体   中英

Task await does not return the result

I am trying to write a function which uses Task and TaskCompletion.

My problem is that after login, the result is not returned. I used similar code before and it was working. I do not know what causes for this situation.

public async Task<byte[]> Sign(byte[] documentContent)
{
    var service = new SignServiceWrapper("https://example.com?wsdl");
    var loginResult = await Task.Run(() => service.Login(loginRequest));

    //....
}

and my SignServiceWrapper class

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;
    }

    // ...
}

If I call my login function like that it works

var loginResult = Task.Run(() => service.Login(loginRequest));
loginResult.Wait();

I know that there is kind of a deadlock but I don't know how to solve this here and which object.

Here is a working .NET Fiddle .

I think your .Login method is trying to do too much. The first thing that I noticed (and can only imagine how it's implemented) is the static ClientGenerator , that has static mutable state . This which is alarming and a very specific code smell. I would love to see what the client itself looks like and how that is implemented as that would certainly help to better answer this question.

Based on what you shared thus far (and assuming that the client.loginAsync returns a Task<loginResponse> ), I would say that you could do the following:

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);
    }

    // ...
}

You could then consume this as such:

public async Task<byte[]> Sign(byte[] documentContent)
{
    var service = new SignServiceWrapper("https://example.com?wsdl");
    var loginResult = await service.LoginAsync(loginRequest);

    //...
}

If the client.loginAsync doesn't return what you're looking for, then you'll need to approach this doing something similar to your current approach . Or if you are locked in to the event-based async pattern , you have other considerations - like whether or not you want to support cancellation, IsBusy , progress, incremental results and if you have the ability to have the event args inherit the System.ComponentModel.AsyncCompletedEventArgs , etc...

One final consideration, if the client.loginAsync is Task returning, even if it doesn't return the loginResponse you need to await it like so:

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;
}

Update

After discussion with OP this .NET Fiddle seemed to align with his needs.

Change var loginResult = await Task.Run(() =>service.Login(loginRequest)); To var loginResult = await service.Login(loginRequest);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM