24

I have a bunch of .NET Webservices running in one IIS Application. These webservices are consumed by another IIS Application (frontend). The first call is pretty slow, about 5 to 10 seconds. After that it’s just milliseconds. The first call is considered a performance problem.

We’ve tried an application that calls all these webservices but this obviously doesn’t solve anything. So it's not the default Application Recycle that is the problem. I've created an application that just initializes the service several times and measures the time it takes to create one instance. Before running this application I ensure that my webservice application is started / recycled, then I run the application. The first initialization takes between 2 to 4 seconds, all others is just milliseconds.

Another thought is that we create a page in the Frontend application that initiates all the webservices and that we call this page before any users are in. I don’t consider this as an elegant solution, what else could I try?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Remco Eissing
  • 1,275
  • 2
  • 12
  • 15

7 Answers7

37

The delay that is experienced when a client is calling a webservice for the first time is caused by the fact that by default a XmlSerializers dll for the webservice needs to be compiled. This is causing the 2-4 seconds for the initial call. Of course this is the case when the webservice application is already running, if it's not you would have a recycle. In which case the other answers could help.

To speed up the initial call you can create the XmlSerializers dll at compile time. You can do this by setting your project build 'Generate serialization assembly' to on. This generates an MyApplication.XmlSerializers.dll containing the webservice information. Now the initial call dropped to 300 ms, presumably the loading of the dll. All calls there after take 0 ms.

In Visual Studio right click on your project and choose 'Properties'. Go to the 'Build' Tab. There you have an option 'Generate Serialization assembly' in the 'Output' section. If you change the value to 'On' the serialization assembly will be generated during compile time.

Remco Eissing
  • 1,275
  • 2
  • 12
  • 15
  • 1
    Interesting. The default setting of "Auto" should do this at compile time according to the docs. I wonder if you are precompiling any of the sites? Precompiling both client/server should solve all your startup issues I would guess. Now that I understand that you are calling a webservice from another web app ... I just wanted to warn you about that. The performance is terrible and doesn't scale at all. The serialization from objects->soap over http and back from soap->objects is rough. – Chad Grant Apr 27 '09 at 02:48
  • So if I understand this correctly, you better always generate a XmlSerializers dll for webservices which improve the initial load performance without any down-side, besides that there are now 2 dll's? – freggel May 27 '09 at 12:24
  • This is perfect, thank you. For reporting services specifically, this will make a huge dfference. http://stackoverflow.com/questions/751762/slow-startup-of-sql-reporting-services-2008-in-native-mode – Praesagus Feb 24 '10 at 21:50
10

The first time you call the webservice, or the first time after a long delay, the web service needs to start up. This is where you're seeing the delay. After that, it's already started and will respond really quickly to calls. This is standard web service behaviour.

You could configure IIS to have keepalive = true - which may improve the performance.

More information as requested.

It could be that the serialization assemblies are being created at runtime. You can change the settings of the serialization assembly using the dropdown at the bottom of the Build pane of the properties window for the project.

It could be that you have written your web service to perform a lot of operations on application start, which would happen the first time a method on the service is called.

It might be that the operation is very slow, but you are then caching the response, which makes subsequent calls faster.

Fenton
  • 241,084
  • 71
  • 387
  • 401
  • That's a very nice suggestion. Unfortunately the system administrators have a daily reboot policy. – Remco Eissing Apr 24 '09 at 09:23
  • 2
    @Smazy: do you know their reasoning for the policy? It sounds like they've still got the Win95/98 fear. Do they require all computers to be formatted and have their OS's reinstalled every 3 months too? :-D – STW Aug 13 '09 at 17:03
  • Not a problem! Hope it helps. – Fenton Feb 25 '10 at 08:03
  • 1
    IIS ("HTTP") Keepalives are unlikely to be the correct answer. Disabling idle timeouts for the App Pool are more likely to have a better outcome - that prevents the Worker Process going away after 20 minutes of inactivity (which would then cause a process to be started on the next request). – TristanK Aug 30 '13 at 01:01
5

I recently discovered that in our ASMX-files we only referred to the class name. We got the service implementation in a different assembly for each ASMX-file. This causes .NET framework to scan through the entire bin-folder looking for the assembly containing the implementation. As your webservice application grows this will consume more time. This can be solved by not only including the class name in your ASMX definition but also the assembly name.

Our ASMX looked like this:

<%@ WebService Language=”C#” CodeBehind=”MyService.cs” Class=”MyWebservice” %>

If you change it to include the assembly that contains the implementation it would look like this. This saved us around 10% of our initial load of the webservice application.

<%@ WebService Language=”C#” CodeBehind=”MyService.cs” Class=”MyWebservice, MyWebservice.Implementation.Assembly” %>

Remco Eissing
  • 1,275
  • 2
  • 12
  • 15
4

That is typical, since ASP.NET apps compile and load the bin\ directory into memory at first request.

Things to do first:

Remove all unnecessary dll's in your bin directory. (I've seen people ship nunit.dll)

Precompile your ASP.NET app so that IIS does not need to. See "VS 2008 Web Deployment Project Support Released"

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Chad Grant
  • 44,326
  • 9
  • 65
  • 80
2

Not sure if this will solve slow spin up of the WS on the "very first time", as I assume there is a load of compiling and .net DLL's being loaded, but you can almost eliminate any future cold starts by ensuring the application pool the WS is in is configured correctly.

By default, IIS6 has "respawn" on idle, after a number of minutes or "recycle" events that effectively restart the WS each time. If your happy the service is stable then these are not needed.

Ensuring that the WS has it's own dedicated application pool (is not sharing an inappropriate pool) is also a strong recommendation.

Guy
  • 9,720
  • 7
  • 38
  • 42
1

After several hour of insane testing, i has been able to reduce the webservice first-run execution time to bare minimum from two host in the same IP class (below 300msec)....

I experienced at first an initial delay of 2-3 sec at first webservice call, than any subsequent call from the same process to be very fast.

The key for understanding the delay in my case was how client handles WEB PROXY !!

This is my new binding in app.config file:

  <basicHttpBinding>
    <binding name="CreateContextSoap" closeTimeout="00:01:00" openTimeout="00:01:00"
        receiveTimeout="01:00:00" sendTimeout="01:00:00" allowCookies="false"
        bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
        maxBufferSize="16777216" maxBufferPoolSize="524288" maxReceivedMessageSize="16777216"
        messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
        useDefaultWebProxy="false">
      <readerQuotas maxDepth="32" maxStringContentLength="1048576" maxArrayLength="16384"
          maxBytesPerRead="65536" maxNameTableCharCount="16384" />
      <security mode="None">
        <transport clientCredentialType="None" proxyCredentialType="None"
            realm="" />
        <message clientCredentialType="UserName" algorithmSuite="Default" />
      </security>
    </binding>
  </basicHttpBinding>

The first webcall execution i suppose to be much slower because transport channel need to discover proxy configuration on initialization, in order to transparently connect to internet. This is usually not needed into intranet environment, thus i have changed these binding settings to avoid use the default proxy (automatically discovered from explorer settings):

bypassProxyOnLocal="false"

useDefaultWebProxy="false"

The first-call connection time is now reduced by a large amount. Hope this helps.

0

Sorry for the necro add, but this has been an ongoing struggle for me as well, and I wanted to add some info to the picture. VisualStudio itself adds a rather large component to the time. Here's the basic test, involving a bare-bones forms app and an already-running webservice hosted internally on a company server (with Generate Serialization Assembly set to true for all tests):

Running in VS, Debug:
    First Call: 400 ms to set up client object, 450 to call function
    Second Call: 1 ms to set up client object, 14 to call function
Running as .exe, Release:
    First Call: 20 ms to set up client object, 70 to call function
    Second call: 1 ms to set up client object, 4 to call function
Running the Debug's .exe file outside of vs:
    First Call: 20 ms to set up client object, 80 to call function
    Second call: 1 ms to set up client object, 4 to call function
Running as Release within VS:
    Similar results to Debug in VS -- very slow

Short story? Visual Studio is adding a large chunk of time to the picture. Instead of ~90 ms, it's taking nearly a second. So if you're doing performance tuning, make sure you do your testing outside the VisualStudio environment.

Kevin
  • 2,133
  • 1
  • 9
  • 21