3

I have an external service that is very fast (responses faster than 50ms in SoapUI tests).

But when I use this service inside my .NET Core application, it takes > 500ms on my development machine. (And over 1 second in the production server)

I noticed that Visual Studio only generates "Async" methods for the methods of the external service. So I have a doSomething() method on the service, and .NET maps it to doSomethingAsync().

To call this method, I just add a ".Result" in the end, as I need the response and I don't need it running asynchronously.

var result = client.doSomethingAsync().Result;

I have here a profiler (DynaTrace) looking at the server and it is showing a call to SendAsync() method to call the external service URL. I don't use any SendAsync() on my application. I don't even have any HttpClient class instance on my code!

DynaTrace profiler SendAsync call

I guess .NET is somehow encapsulating my synchronous call inside an asynchronous call, and then just waiting for the response to resume code execution... And I guess it's creating a lot of overhead processing for something that should be simple and fast.

So the question is: How can I make the external service method calls faster in .NET Core?

Bellow is the relevant part of the code:

EndpointAddress address = new EndpointAddress(baseExternalAccess.UrlService);
BasicHttpBinding binding = new BasicHttpBinding();
binding.MaxReceivedMessageSize = 2147483647;
binding.OpenTimeout = new TimeSpan(1, 0, 0);
binding.SendTimeout = new TimeSpan(1, 0, 0);
binding.Security.Mode = BasicHttpSecurityMode.Transport;
Stopwatch stopwatch = new Stopwatch();
using (MyServiceSoapClient cliente = new MyServiceSoapClient(binding,address))
{
    stopwatch.Reset();
    stopwatch.Start(); 
    var result = cliente.doSomethingAsync().Result;
    stopwatch.Stop();
    logger.Information("Time: " + stopwatch.ElapsedMilliseconds.ToString() + "ms");
}

Edit: To clarify the problem, I create two new projects from scratch. One using .NET Core and another one using .NET Framework.

.NET Core

  1. Right Click on the Project
  2. Add -> Connected Service
  3. Choose "Microsoft WCF Web Service Reference Provider"
  4. Inform the service wsdl URI, click GO
  5. Inform a Namespace, click Next
  6. Change nothing, click Finish
  7. Wait for Visual Studio to discover the service and create it's stuff.

.NET Framework

  1. Right Click on the "References" -> Add Service Reference...
  2. On the Address box, inform the service wsdl url, click GO.
  3. Inform a Namespace, click "Advanced"
  4. Uncheck "Allow generation of asynchronous operations", click OK.
  5. Click Ok and wait for VS to create it's stuff.

Then, on both projects, I made a simple call to the same method using same parameters. In fact, the code is almost the same, the only difference is that on the .NET Core version, the method name is "doSomethingAsync()" and I have to use ".Result" after the method name, while in the .NET Framework version, the method name is "doSomething()" and I can call it directly.

Edit 2: Every time I run this test I get similar results... The first call to the service method always is ~700ms faster on the .NET Framework version. The next 9 calls has similar timings (but the .NET Framework is always slightly faster).

On my program, I just need to call the service once, so only the time of the first call is important to me.

Edit 3: Ok, looks like .NET Core has some overhead delay to access web services.

I made four versions of a C# Console Application that only makes 10 requests to this external service and measure the time using a Stopwatch:

  • .NET Framework 2.0 (Using Web Reference)
  • .NET Framework 4.6.1 (Using WCF Service Reference)
  • .NET Core 2.1 (Using WCF Web Service Reference)
  • .NET Core 2.2 (Using WCF Web Service Reference)

Here are the results:

Test .NET Framework 2.0 Web Reference
Time: 1502ms
Time: 762ms
Time: 693ms
Time: 728ms
Time: 763ms
Time: 644ms
Time: 845ms
Time: 688ms
Time: 667ms
Time: 676ms
Total time: 7993ms

Test .NET Framework 4.6.1 WCF Reference
Time: 1770ms
Time: 675ms
Time: 619ms
Time: 644ms
Time: 895ms
Time: 671ms
Time: 611ms
Time: 702ms
Time: 655ms
Time: 741ms
Total time: 8251ms

Test .NET Core 2.1 WCF Reference
Time: 2984ms
Time: 759ms
Time: 899ms
Time: 874ms
Time: 756ms
Time: 792ms
Time: 922ms
Time: 1001ms
Time: 767ms
Time: 679ms
Total time: 10810ms

Test .NET Core 2.2 WCF Reference
Time: 3167ms
Time: 796ms
Time: 707ms
Time: 732ms
Time: 929ms
Time: 828ms
Time: 775ms
Time: 847ms
Time: 957ms
Time: 884ms
Total time: 10877ms

As the results shows, the biggest issue is with the first request. It takes longer than the other 9 request and the final 9 requests have similar timings on all te tests (But .NET Core ones are still slightly slower).

My application makes only one request to the Web service, so only the first call time is important to me.

So my conclusions is that .NET Core is just slow with WCF Web Services.

Daniel Ribeiro
  • 498
  • 1
  • 4
  • 15
  • ok so just to clarify, adding .Result does not make the call synchronous. It just blocks the current thread while waiting for the return of the async call. The call is still async, you are just not awaiting it – hawkstrider Feb 19 '19 at 19:15
  • Yes @bhmahler. I know. But I don't know how to do a "pure sync" call using .NET Core. I guess it'll solve my problem if it's possible. – Daniel Ribeiro Feb 19 '19 at 19:24
  • I have not worked with soap services in .net core. Perhaps your MyServiceSoapClient class implements non async methods. – hawkstrider Feb 19 '19 at 19:28
  • With WCF under the regular framework, async is an option. Don't you have a plain DoSomething() method? Looked at all the options in the add-service wizard? – H H Feb 19 '19 at 19:28
  • Are you using "Add Service Reference" dialog? If yes, have you checked the "Advanced" options, especially the "Allow generation of asynchronous operations" check box? – Ivan Stoev Feb 19 '19 at 19:28
  • I have added the WCF tag, but review that and add all relevant info about which packages/tools you are using. .net Core and SOAP is new. – H H Feb 19 '19 at 19:30
  • Perhaps this may shed some light https://stackoverflow.com/questions/47259297/wcfclient-operation-only-async-net-core-2-0 – hawkstrider Feb 19 '19 at 19:31
  • I added some useful information to the question. Also, I did test results that proved me that .NET Framework service calls are faster than .NET Core ones. – Daniel Ribeiro Feb 25 '19 at 19:34
  • Is it same machine on which both test are running? Application is deployed on IIS with optimizations or running from visual studio in debug mode? Performance can change based on various more factors. I upvoted already since issue is genuine but looking for your reply for better solution – Pranav Singh May 08 '19 at 07:32
  • Yes @PranavSingh. I did run all the four tests on the same machine (my dev machine, using VS). I did not published the tests on the production server as the server is behaving just like my machine is (but even slower). What I ended up is reworking on my process in a way that my application do the Web Service request "before" user asks for it... So when user finally asks for it, the response is already cached on my database. It's not a solution for the slow behaviour of .NET Core requests but it solved my problem. – Daniel Ribeiro May 08 '19 at 19:55
  • I experienced a similar problem. Call to SOAP service was fast when it was .NET 4.5.1. Porting the call to .NET Core has made it very slow with the connection sometimes timing out. Solution in the end was for .NET Core to make REST call to service in .NET 4.6.1 which then calls SOAP service. Somehow, this is much faster than .NET Core calling SOAP direct – josagyemang May 14 '19 at 10:06
  • I was trying to avoid creating a dummy layer... But for now this is the best "solution". Thanks for the advice @josagyemang – Daniel Ribeiro May 15 '19 at 11:49
  • 1
    I ported WPF app to .NET Core and I've noticed that it became less responsive. After clicking a button the HTTP request is executing much longer than on .NET Framework and it gives freezing effect for 2 seconds which didn't happen before! I would love to use .NET Core but due to this problem I can't – Konrad Dec 04 '19 at 11:32

0 Answers0