2

I have the following ServiceStack web service

public class RetreadServices : Service
{
    public IRepository Repository { get; set; }

    //http://stackoverflow.com/questions/18902135/servicestack-no-server-side-async-support

    public async Task<ValidationResponse> Get(RetreadSsnInfoAsync request)
    {
        return await Task.Factory.StartNew(() =>
        {
            Tenant.SetTenant(request.TenantId);
            return new ValidationResponse { Result = Repository.CannotRetreadSsn(request.Ssn) };                    
        });
    }

    public async Task<ValidationResponse> Get(RetreadEmailInfoAsync request)
    {
        return await Task.Factory.StartNew(() =>
        {
            Tenant.SetTenant(request.TenantId);
            return new ValidationResponse { Result = Repository.CannotRetreadEmail(request.Emails) };
        });
    }

    //more methods constructed in the same fashion

}

then in a separate class in my application I have this method (based off of code from @StephenCleary)

private async Task<ValidationResponse[]> DoOperationsConcurrentlyAsync(string tenantId, string[] emails, string ssn)
{
    Task<ValidationResponse>[] tasks =
    {
        ResolveService<RetreadServices>().Get(new RetreadEmailInfoAsync { TenantId = tenantId, Emails = emails }), 
        ResolveService<RetreadServices>().Get(new RetreadSsnInfoAsync { TenantId = tenantId, Ssn = ssn })
    };

    await Task.WhenAll(tasks);

    ValidationResponse[] result = new ValidationResponse[tasks.Length];

    return result;
}

and being invoked like this

synchronous code...
synchronous code...

var result = DoOperationsConcurrentlyAsync(request.TenantId, request.Emails, request.Ssn);

synchronous code...
synchronous code...

The goal of all of this is to wait while the tasks process in parallel and hopefully decrease my over-all time... but the DoOperationsConcurrentlyAsync needs to block, how do I do that? Then as a bonus, how do I pass the return values back from the individual tasks up and out of the method with the async modifier?

Daniel Mann
  • 57,011
  • 13
  • 100
  • 120
Stephen Patten
  • 6,333
  • 10
  • 50
  • 84
  • 2
    You can use `Task.WaitAll(Task array)` or see this link: http://stackoverflow.com/questions/5095183/how-would-i-run-an-async-taskt-method-synchronously – Behzad Jun 13 '15 at 03:50
  • 3
    On a side note, this (`return await Task.Factory.StartNew(() =>`) is exactly the wrong approach on the server side. It would be more efficient to remove the `async`, `await`, and `StartNew` on the server side. (The client can still be asynchronous even if the server is synchronous). – Stephen Cleary Jun 13 '15 at 13:50
  • @StephenCleary I knew that comment was coming, I have at least 3 tabs open right now where you explain the issues with StartNew. I've actually changed the code to use TPL. – Stephen Patten Jun 14 '15 at 13:25
  • @StephenCleary on a side note, what if I did want to do async on the server since we're using IHttpAsyncHandler , how would you construct the server-side code? – Stephen Patten Jun 14 '15 at 13:36
  • @Stephen: Neither `StartNew` nor `Task.Run` is appropriate here. If you have asynchronous code, then just call it using `await`. If you have synchronous code, then just call it directly. In this case, `StartNew`/`Run` will only add overhead without any benefit. – Stephen Cleary Jun 14 '15 at 17:23

1 Answers1

4

I hope I'm understanding this correctly. But don't you just need to add the await keyword?

synchronous code...
synchronous code...

var result = await DoOperationsConcurrentlyAsync(request.TenantId, request.Emails, request.Ssn);

synchronous code...
synchronous code...

EDIT: Bonus question: Again, I hope I'm understanding you correctly...

But I would replace this:

await Task.WhenAll(tasks);

ValidationResponse[] result = new ValidationResponse[tasks.Length];

return result;

...with simply this:

return await Task.WhenAll(tasks);

That should work the way you want it.

sstan
  • 35,425
  • 6
  • 48
  • 66