1

I' am developing a WebApi with the latest ASP.Net 5 RC1. The data provider is a third-party WCF service. I only have the contract (shipped as a dll which contains the service interface) and I want to call service operation asynchronously but that wcf service does not provide async operations. So I just try to figure out the right pattern I should use. So currently, the service client class looks like this (MyServiceClient : IMyServiceClient):

ChannelFactory<IServiceInterface> channelFactory;

...

public IResult DoAServiceCall(object param)
{
     var channel = channelFactory.CreateChannel();
     return channel.DoSomething(new Request() {Param = param});
}

public async Task<IResult> DoAServiceCallAsync(object param)
{
    var result = await Task.Run(() => DoAServiceCall(param));
    return result;
}

And the WebApi controller is like this:

public class SampleController : Controller
{
    private IMyServiceClient serviceClient;

    public SampleController(IMyServiceClient serviceClient) 
    {
        this.serviceClient = serviceClient
    }

    [HttpGet]
    [Route("api/getsomething")]
    public async Task<IResult> Get(int p)
    {
        return await serviceClient.DoAServiceCallAsync(p);
    }
}

Is this a good pattern to do an asynchronous service call? Or what is the good and effective implementation of this case?

Thank you in advance.

stratever
  • 586
  • 4
  • 11
  • @Dai - It will free up the request thread to serve other requests until the result has been received from the WCF service. Without knowing how many simultaneous incoming requests there will be and how long each request will take to await a response I would say trying to await the network I/O is a good idea. – Igor Feb 10 '16 at 21:55
  • Maybe a duplicate question. [Pattern for calling WCF service using async/await](http://stackoverflow.com/questions/18284998/pattern-for-calling-wcf-service-using-async-await) – Igor Feb 10 '16 at 21:58
  • @Igor : The WCF service is a third party service, I am not able to generate an async service client with scvutil because the wsdl endpoint is not available to me. I only have a dll which contains the service interface. – stratever Feb 10 '16 at 21:58
  • Could you reverse engineer the DLL if this is nothing more than a bunch of call through and add async support to it? Or is that not an endeavor you are willing to take on. – Igor Feb 10 '16 at 22:00
  • Just adding `var result = await Task.Run(() => DoAServiceCall(param));` does nothing more than free the current thread but puts the burden on another thread. It might even be detrimental as now you are working with 2 threads per request instead of 1. – Igor Feb 10 '16 at 22:02
  • Presumably this will be hosted in iis, iis will create new threads for every request into your web api application anyway. So the request will not be blocking. What is the point of returning a task and trying to serialise it into a http response, you would get no notification once it left the application domain. This looks very strange to me. – Alexis Coles Feb 10 '16 at 22:03
  • 1
    @Igor is right. Using `Task.Run()` makes things worse. – Anthony Chu Feb 10 '16 at 22:05
  • @Igor - Yes, i could with ILSpy and it contains only a public interface with [OperationContract] attributes. – stratever Feb 10 '16 at 22:07
  • @Alexis Coles - My target is to perform an async response to the Javascript client. This WCF service in some situation can be very slow and this is why i want to perform the service call asynchronously – stratever Feb 10 '16 at 22:07
  • web request are always async, you don't need to do anything to make this asynchronous as far as the client is concerned. – Alexis Coles Feb 10 '16 at 22:08
  • yes, but this thread will be hanging until the wcf client respond – stratever Feb 10 '16 at 22:10
  • not the javascript thread, only a thread in the web api, and what does that matter. threads are cheep. – Alexis Coles Feb 10 '16 at 22:11
  • @Alexis Coles - So you suggest to make the service call synchronously and it will not cause any performance issue even if the service responds slowly in some situation? – stratever Feb 10 '16 at 22:14
  • Async/await pattern has never been about performance really. It is about offloading I/O calls so the thread can be freed up to do something else. You will only notice a difference if you have a very high number of simultaneous requests where all threads are waiting for I/O to complete and there are no threads left to serve the incoming requests. – Igor Feb 10 '16 at 22:16
  • I suggest that you couldn't make a synchronous request to webapi over http if you tried, all request are inherently async. presumably you will be using some sort of ajax request from javascript where you would make a request and then define a handler to be performed when the result comes back async, the ui thread on the client will be free to do what ever it needs to in the meantime. – Alexis Coles Feb 10 '16 at 22:17
  • @Igor - And in this case (very high number of simultaneous requests) how should i handle it (how to manage the wcf service call)? – stratever Feb 10 '16 at 22:19
  • @Igor So how is that not "performance". I think you mean that async/await isn't about speed. – Kenneth K. Feb 10 '16 at 22:19
  • @KennethK. - correct. I mean the name async is somewhat misleading as people automatically assume async = parrallel = faster. Its not the case, if an I/O request takes 15 seconds to complete it will take 15 seconds with or without an await on it. That is what I was trying to convey. – Igor Feb 10 '16 at 22:21
  • 2
    @stratever - It seems you do not have much of a choice. You either rebuild/create your own wrapper that is async callable and actually awaits the I/O network call (not just passing the call along to `Task.Run`) or you call the wrapper as is in a synchronous manner. Which way you go depends on your requirements or load expectations. – Igor Feb 10 '16 at 22:24
  • 1
    @stratever: `My target is to perform an async response to the Javascript client.` - but `await` won't do that. [`Async` doesn't change the HTTP protocol](http://blog.stephencleary.com/2012/08/async-doesnt-change-http-protocol.html); if you want to "return early" or "fire and forget" then you'll need [different techniques](http://blog.stephencleary.com/2014/06/fire-and-forget-on-asp-net.html). (All links are to my blog) – Stephen Cleary Feb 10 '16 at 22:27
  • @Igor - Yes, a wrapper service sounds good. – stratever Feb 10 '16 at 22:32
  • @Stephen Cleary - Is QBWI supported in ASP.Net 5 RC1 (or is there an implementation which compatible with .net core 1.0 )? – stratever Feb 10 '16 at 22:35
  • @Igor - Your wrapper idea will be accepted as an answer, so please write an answer – stratever Feb 10 '16 at 22:45
  • Thank you everyone for this short discussion. It helped me a lot! – stratever Feb 10 '16 at 22:56
  • @stratever: I don't know about QBWI on ASP.NET Core. – Stephen Cleary Feb 11 '16 at 00:52

1 Answers1

1

As just discussed in the comments your best bet would be to do one of these:

  1. Create your own custom wrapper that awaits the actual network I/O call. So not just a call to Task.Run.
  2. Use the wrapper as is and have synchronous calls.

Just to clarify. The async/await pattern is used for offloading I/O calls from CPU bound threads. This will allow the server to handle more simultaneous requests depending on the nature of the calls.

The calls from the client, (especially like JavaScript) will not be influenced either way. Almost all JavaScript calls are asynchronous by default in that they have a callback when the operation completes (there are ways to override this and have the JavaScript call wait on the return but this is usually never done).

Igor
  • 60,821
  • 10
  • 100
  • 175