CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Steve Hebert's Development Blog

Steve's Blog - From .Net to dotMath and everything in between.

July 2006 - Posts

  • Asynchronous Webservice Calls – the Truth behind the Begin… End… functions – Part II

    In my previous post on this topic,  I concluded with three key points:
    • The Begin function does not actually initiate the physical call on the wire – it simply places these calls into a queue to be processed later. 
    • Due to point #1, if you are making multiple asynchronous calls while varying the parameters on an input struct or class, you must deep-copy that structure before passing.
    • Due to a maximum of two calls being made at any one time,  I recommended that you handle the asynchronous calls yourself via a threadpool. 

     

    While the first two points hold, it turns out the maximum number of simultaneous calls is, in fact, a way of playing nice. As I mentioned in the earlier post, flooding a public server with too many simultaneous requests may result in being pegged as a DoS attack. Thanks to SecretGeek's comments and  Tomas Restrepo's blog entry, they opened some questions with my conclusions pointing to their own experiences around connection handling.


    If you wish to pipeline requests, you need to look at key issues with setting up the client machine and the server.  Unfortunately, the client-side still uses multiple threads to handle the requests (instead of using overlapped IO), but at least I don't have to manage the threadpool myself.  


    Configuring the Client

     

    The client can handle more than two simultaneous asynchronous requests and the configuration bits lie in machine.config.  By default, the maxconnection setting within .Net is defaulted to “2” for any given address/port. You can change this setting system-wide or specify configurations for specific addresses.   

     

    <system.net>
        <connectionManagement>
            <add address="*" maxconnection="2"/>
        </connectionManagement>
    </system.net>

     

    Setting this value to “20” allows all requests on the test call I put together to be fired simultaneously.  (Note that I couldn’t get this to actually work with more than 10 on my development box – reasons below.) Keep in mind that in setting this value, you must also be mindful of a host of other threading settings – maxWorkerThreads, maxIOThreads, minFreeThreads and minLocalRequestFreeThreads.  For a more thorough discussion on this topic, check out Tess’ blog entry on this topic

     

    Configuring the Server

     

    Getting these requests to be serviced simultaneously under IIS 5.x and Windows XP is another story.  When I set the maxconnection setting, my local IIS webserver responded with a 403 error.  It continued responding with the 403 error for several minutes. 

     

    Feeling like a server error, I verified the problem in a KB article stating that IIS is honoring the 10 connection limit of XP Pro.  The KB does mention that turning off HTTP Keep-Alives under IIS will improve the performance in this instance, but I didn’t see any changes when trying to set maxconnection to anything larger than 10.

     

    I’m on vacation this week, so I’m not sure how Win2k3/IIS6 will respond with a flood of webservice calls and how HTTP Keep-Alives play into this performance.  That will be a posting for another day.

     

  • Asynchronous WebService calls – the truth behind the Begin… End… functions

    I’ve finally solved this one – not that the resolution makes me happy, but it’s nice to finally explain the behavior.

    I ran into a funny behavior four years ago with WebService calls on the .Net platform.  At that time, my idea was to launch webservice calls simultaneously against multiple backend webservices.  The effect would be the pipelining of these requests.

    To illustrate, if I make a total of ten 5-second requests sequentially, the total run time from my client is ~50 seconds.  If I make a total of ten 5-second pipelined requests,  my client runtime is reduced to ~5 seconds.  In my time estimates I’m factoring out call overhead, but the pipelined requests are potentially more efficient because the IP transmission overhead is overlaid as opposed to being sequentially blocked.

    While I could launch these from multiple worker threads, the existence of the Begin… End… functions is far more compelling.  This is because the webservice calls are fully blocking to the client application and really wastes a perfectly good thread.  I’d much rather launch the functions and hold onto a synchronizing object to tell when the processing is complete.  With the Async methods, I don’t need to synchronize worker threads and buy into that complexity. It sounds good…

    After running into this same fundamental problem again (different calling behavior, but same pipelining idea), the behavior is different than I expected based on the documentation. I decided to do some more digging and resolve this once and for all.

    To illustrate, let’s take a simple WebService function exposed on a service called SimpleService:

            public struct Bar
            {
                public int i;
            }

            [WebMethod]
            public int Foo( Bar bar )
            {
                System.Threading.Thread.Sleep(2000);
                return bar.i;
            }

     

    Next, let’s take some client code to make everything clear:

     

            // this class hold the details needed to get results back
           
    // which include the web service instance and the IAsyncResult

            public class AsyncDetails
            {
                public SimpleProcess Function;
                public IAsyncResult AsyncResult; 

                public AsyncDetails( SimpleProcess function, IAsyncResult result )
                {
                    Function = function;
                    AsyncResult = result;
                } 
            }

     
            public void TestRun()
            {
                ArrayList results = new ArrayList();
                SimpleProcess process = new SimpleProcess();
     

                // note - the behavior only becomes obvious when passing
               
    // a struct or class - value parameters only help mask the
               
    // real underlying behavior.

                Bar bar = new Bar();

                // Launch 20 running instances and aggregate them in an
               
    // ArrayList for further processing

                for( int x = 0; x < 20; x++ )
                {

                    // this works the same whether I use a shared webservice instance or
                    // create a new instance for each call

                    bar.i = x;
                    results.Add( new AsyncDetails( process, process.BeginFoo(bar, null, null)));
                } 
                // next, go through each result and complete processing.
               
    // real-world app would be aggregating results at this point
               
    foreach( AsyncDetails detail in results )
                {
                    // assuming that processing is order dependent...

                    if( !detail.AsyncResult.IsCompleted )
                        detail.AsyncResult.AsyncWaitHandle.WaitOne(); 
                    Console.WriteLine( detail.Function.EndFoo( detail.AsyncResult ));
                }

            }

    So what would you expect the output to be?

    {0,1,2,3,4,5,6,…,19} in roughly 2 seconds?

     

    Wrong.

     The answer is:  {19, 19, 19, 19, 19,…, 19} in roughly 10 seconds!

     

    Why is this?  It turns out my operating assumption is incorrect.  My belief that BeginFoo(…) actually launched a request is completely invalid - it only queues the request.


    If they were run as I expected, my Bar struct would be serialized during my call to BeginFoo(…). Because it’s being queued, the actual physical call being made to Foo is using the shared Bar struct which has a value of 19 when it’s actually made!  Furthermore, when you watch this run in NUnit you’ll see that it’s actually making two requests at a time (two results appear simultaneously, two second wait, two more results appear simultaneously, two second wait…, and so on).


    My answer to this problem four years ago was to place synchronous requests in a worker threadpool and manage the threads – it turns out that was the right call.  After looking at the behavior of .Net, it appears that they are also running these calls on background threads.  When doing this, you have to be conscientious in the number of threads being used to service these requests (especially if you’re making these from within a web application or webservice). 


    I would have hoped the .Net implementation would have been more elegant than my thrown-together threadpool, but it turns out that’s just not the case. Perhaps they could have used Overlapped I/O with sockets available since winsock 2???  I suppose if you are making these calls over the public internet you risk being mistaken as an attemped DOS source

    [Update 7/20/2006 - It turns out the two connection limit is a machine.config level setting.  Check out my followup to this post for more details. While this is configurable, all calls are still being made within .Net's threadpool - so if you are making web service calls from a server-side web application/service, you are dealing with a limited resource.]


    [Note:]

    The MSDN documentation errantly states: The client instructs the Begin method to start processing the service call, but return immediately.  It's the "start processing the service call" line that should be reworded to "queue the service call".

  • Executing MSIs remotely

    PsExec is a great utility for executing commands remotely - and it works especially nice for things like installs (MSIs) that require certain permissions during installs.  This is much easier than configuring telnet on the remote server to allow this.  We've been using this on our build servers to push our development and pre-production environments.

    I originally heard of this one from Visual Build Pro - they have a template that relies on PsExec being install on the build machine. 

    PsExec is yet another great utility from SysInternals.


  • Setting up Log4Net

    If you're looking at setting up log4net in your application, I recommend checking out the "Quick and Dirty Guide to Configuring Log4Net for Web Applications". 

    This is a great walk through complete with sample code.  You'll need to dig into the documentation for help with actual config details, but the walk through does a great job of getting your project running with Log4Net quickly.
  • System.IO.FileNotFoundException - running a webservice on Win 2k3

    Here's a bizarre problem I ran into today that I thought could use some google-juice. 

    I am getting the following error when I try to run a new webservice I have
    placed on any one of 4 windows 2003 servers. (Running under ASP.NET 1.1)

    To minimize the problem, I created a simple webservice called "TestApp" that
    exposes [ public int Add( int x, int y ) ] as the lone method on the service.
    I create a simple installer package for the msi and run it on the server.

    When I go to http://.../TestApp/Service1.asmx, the generated page and test
    page appear fine.  When I run the test page, supplying values for x and y and
    upon pressing the submit button, I receive the error message listed below.  
    Each time I execute this, the name of the dll changes.   The names of the
    dlls seem pretty random, none of them turn up on a Windows Live or Google
    search.  The text of this message is completely unformatted - no headers like
    the sample methods normally show on errors.

    The problem appears to be security related - when the application pool user is given admin rights the problem goes away.  Based on the call stack, I'm guessing the CLR JITter is running into problems with the provided assembly. (?)

    System.IO.FileNotFoundException: File or assembly name kciklf5_.dll, or one
    of its dependencies, was not found.
    File name: "kciklf5_.dll"
       at System.Reflection.Assembly.nLoad(AssemblyName fileName, String
    codeBase, Boolean isStringized, Evidence assemblySecurity, Boolean
    throwOnFileNotFound, Assembly locationHint, StackCrawlMark& stackMark)
       at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef,
    Boolean stringized, Evidence assemblySecurity, StackCrawlMark& stackMark)
       at System.Reflection.Assembly.Load(AssemblyName assemblyRef, Evidence
    assemblySecurity)
       at System.CodeDom.Compiler.CompilerResults.get_CompiledAssembly()
       at System.CodeDom.Compiler.CompilerResults.get_CompiledAssembly()
       at System.Xml.Serialization.Compiler.Compile()
       at System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings)
       at System.Xml.Serialization.XmlSerializer.FromMappings(XmlMapping[]
    mappings)
       at
    System.Web.Services.Protocols.XmlReturn.GetInitializers(LogicalMethodInfo[]
    methodInfos)
       at
    System.Web.Services.Protocols.XmlReturnWriter.GetInitializers(LogicalMethodInfo[] methodInfos)
       at System.Web.Services.Protocols.MimeFormatter.GetInitializers(Type type,
    LogicalMethodInfo[] methodInfos)
       at System.Web.Services.Protocols.HttpServerType..ctor(Type type)
       at System.Web.Services.Protocols.HttpServerProtocol.Initialize()
       at System.Web.Services.Protocols.ServerProtocolFactory.Create(Type type,
    HttpContext context, HttpRequest request, HttpResponse response, Boolean&
    abortProcessing)

     

    === Pre-bind state information ===
    LOG: Where-ref bind. Location = C:\WINNT\TEMP\kciklf5_.dll
    LOG: Appbase = file:///C:/Inetpub/wwwroot/TestApp
    LOG: Initial PrivatePath = bin
    Calling assembly : (Unknown).
    ===

     

    LOG: Policy not being applied to reference at this time (private, custom,
    partial, or location-based assembly bind).
    LOG: Attempting download of new URL file:///C:/WINNT/TEMP/kciklf5_.dll.

  • Creating .Net subprojects under a main project site

    There is a decent article on the Web Development Tools Team site about creating web-based subprojects on IIS.  Sub-projects work well for isolating subprojects under one main hat.  I've used this before in long-term migration from ASP->ASP.NET. 

    A few years ago (VS2003), we ran into a problem where Windows XPE clients were causing an obscure runtime error on login.  There was simply no way to log into our application from these boxes.  It turned out that XPE's IE crammed some unexpected information in the HTML header that .Net was choking on.  The problem was verified with MS support and our only solution was to break out the subprojects into top-level projects.

    I did some searches to see if this has been fixed, but I cannot find a reference to it.  I hope VS2005 has fixed it, because from what I've seen, pushing a fix to XPE boxes is more difficult due to the fact that these are often used as terminal-style boxes on LANs. (At least as I've seen them).


More Posts

Our Sponsors