1

I have seen some of the existing questions regarding async waiting for completion , However for me none of the solution work.

I am using a C# wrapper for connecting to sales force https://github.com/developerforce/Force.com-Toolkit-for-NET/

In the below method i want to wait for the method UsernamePasswordAsync to complete execution so that i can get the values from the auth object.

public async Task<Token> GetTokenForSalesForce()
{
    Token token = null;
    try
    {
        var auth = new AuthenticationClient();
         await auth.UsernamePasswordAsync(configuration.Value.ClientId, configuration.Value.ClientSecert,
                                         configuration.Value.SFUsername, configuration.Value.SFPassword,
                                         configuration.Value.SFBaseUrl);
        if (!string.IsNullOrEmpty(auth.AccessToken) && !string.IsNullOrEmpty(auth.InstanceUrl))
        {
            token = new Token
            {
                BearerToken = auth.AccessToken,
                InstanceURL = auth.InstanceUrl,
                ApiVersion = auth.ApiVersion
            };
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
    return token;
}

public async Task<List<SFDashboardResponse>> GetOrderCountFromSalesForce(Token token)
{
    List<SFDashboardResponse> sFDashboardResponses = new List<SFDashboardResponse>();
    try
    {
        var client = new ForceClient(token.InstanceURL, token.BearerToken, token.ApiVersion);
        var response = await client.QueryAsync<SFDashboardResponse>("SELECT something ");
        var records = response.Records;
    }
    catch(Exception e)
    {

    }
    return sFDashboardResponses;
}

The signature in the library is

public async Task WebServerAsync(string clientId, string clientSecret, string redirectUri, string code, string tokenRequestEndpointUrl)
{
}

The problem is while the method wait for await to be first execute another thread executes the other part of the orignal caller.

I call it from here

public IActionResult post()
{
    var authtoken = _salesForceService.GetTokenForSalesForce();
    var response = _salesForceService.GetOrderCountFromSalesForce(authtoken.Result);
    DashboardModel dashboardModel = null;
    if (authtoken.Status == TaskStatus.RanToCompletion)
    {
       fill the object
    }

     return Ok(dashboardModel);
 }
4
  • 1
    I appreciate people who down vote a question , it would be nice if you put a reason with it Commented Aug 28, 2018 at 15:11
  • 4
    Never do throw ex; where ex is a caught exception. You'll lose your stack trace. Just do throw; which will preserve the stack trace. And don't catch an exception if the only thing you're going to do is re-throw it. And don't have an empty catch block in your code. At the very minimum, log the exception. Commented Aug 28, 2018 at 15:19
  • @mason you are correct. Logger is being implemented by another person. Once it is done it will be used in the catch block. Commented Aug 28, 2018 at 15:21
  • You're not awaiting the asynchronous tasks, so of course the code moves on. That's sort of the whole point. Commented Aug 28, 2018 at 15:30

1 Answer 1

5

You can wrap the IActionResult with a Task and await on the tasks below.

public async Task<IActionResult> post()
{
    var authtoken = await _salesForceService.GetTokenForSalesForce();
    var response = await _salesForceService.GetOrderCountFromSalesForce(authtoken);

    DashboardModel dashboardModel = //fill the object

    return Ok(dashboardModel);
}

At least this is what you are asking for as far as I understand, if its another problem let me know.

EDIT 1:

This is just my suggestion/opinion.

Personally I dont really like having the code wrapped in try-catch everywhere, this way the code can be hard to read and maintain. You really should consider centralizing exception handling in one place, you could have a base controller or just a middleware like this one:

public class ErrorHandlingMiddleware
{
    private readonly RequestDelegate _next;

    public ErrorHandlingMiddleware(RequestDelegate next)
    {
        this._next = next;
    }

    public async Task Invoke(HttpContext context, ILogger logger)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        { 
            await HandleExceptionAsync(context, ex, logger);
        }
    }

    private static Task HandleExceptionAsync(HttpContext context, Exception exception, ILogger logger) 
    {
        logger.Log(exception);
        //do something
        return context.Response.WriteAsync(... something ...); //Maybe some JSON message or something
    }
}

The you just register it as a middleware in the Configure method like below:

app.UseMiddleware<ErrorHandlingMiddleware>();
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.