Sooraj
Sooraj

Reputation: 133

Async / Await Pattern. How to pass a await-able method to another method

In my application I need to call a method before all the API request. If a specific condition met then I need to execute set of statements in that method.

In order to generalize this I created a helper class something like this.

public class CertificateValidator {
readonly IDependencyService _serviceLocator;
public CertificateValidator(IDependencyService serviceLocator) {
    _serviceLocator = serviceLocator;
}

public async Task <T> TryExecuteWithCertificateValidationAsync <T> (Task <T> operation) {
    var service = _serviceLocator.Get <IDeviceService> ();
    if (service.CertificateValidationRequired()) {
        // My Code.
    }
    T actualResult = await operation;
    return actualResult;
}

}

And In my viewmodel I have done something like this.

 public CertificateValidator ValidateCertificate => new CertificateValidator(_serviceLocator);

var response = await ValidateCertificate
                            .TryExecuteWithCertificateValidationAsync(MyMethodAsync());

private async Task<RequestResult<Response>> MyMethodAsync()
{
     // Some code
}

But when I implement like this the execution flow is

And my doubt here is,

I need to execute the TryExecuteWithCertificateValidationAsync completely and then followed by MyMethodAsync.

In short as I said early, I need to execute set of code before I call all my API calls. How I can achieve something similar using async an await.

Upvotes: 3

Views: 232

Answers (1)

Johnathan Barclay
Johnathan Barclay

Reputation: 20353

Rather than passing a Task pass a function:

public async Task<T> TryExecuteWithCertificateValidationAsync<T>(Func<Task<T>> operation)
{
    var service = _serviceLocator.Get<IDeviceService>();
    if (service.CertificateValidationRequired())
    {
        // My Code.
    }
    T actualResult = await operation();
    return actualResult;
}

var response = await ValidateCertificate
    .TryExecuteWithCertificateValidationAsync(MyMethodAsync);

Update as per comment

If the method requires arguments, the types need to be prepended as additional generic arguments to Func:

private async Task<RequestResult<Response>> MyMethodAsync(int i)
{
     // Some code
}

public async Task<T> TryExecuteWithCertificateValidationAsync<T>(Func<int, Task<T>> operation) // Add int as second generic argument
{
    T actualResult = await operation(1); // Can now be called with an integer
    return actualResult;
}

Upvotes: 2

Related Questions