Leveraging multi-threading when calling Web Services or SQL Server

If you need to make more than one call to one or more web services in your code in a single request, then you can do this using multiple threads for vastly better performance.

 

There are three ways of solving this problem, depending upon which layer your code resides (UI, Business Layer or Data Layer).

 

If your code is in the UI layer, then you can make use of the Async parameter in your ASPX:

 

<%@ Page Language="C#" Async="true" CompileWith="SlowWSAsync.aspx.cs" ClassName="Whatever.SlowWSAsync_aspx" %>

 

like this (SlowWsAsync.aspx.cs):

 

using System.Threading;

 

namespace Chevron.UpstreamArchitecture.Services.Whatever

{

  public partial class SlowWSAsync_aspx

  {

    // Get an instance of our Slow Web Service

    Slow slowWebservice = new Slow();

 

    void Page_Load(object sender, EventArgs e)

    {

      BeginEventHandler bh = new BeginEventHandler(this.BeginGetAsyncData);

      EndEventHandler eh = new EndEventHandler(this.EndGetAsyncData);

      AddOnPreRenderCompleteAsync(bh, eh);

    }

 

    IAsyncResult BeginGetAsyncData(Object src, EventArgs args, AsyncCallback cb, Object state)

   {

      // Note - this is serviced on the same thread as Page_Load

      // but a different thread is used to service EndGetAsyncData

      //

      return slowWebservice.DoWhatever(cb, state);

    }

 

    void EndGetAsyncData(IAsyncResult ar)

    {

      string ret = slowWebservice.DoWhatever (ar);

    }

  }

}

 

If you’re in the Business layer, then you can use something like this:

 

using System.Threading;

 

namespace Chevron.UpstreamArchitecture.Services.Whatever

{

 

    class ConsoleApp

    {

        static void Main(string[] args)

        {

            DoStuffSimultaneously doit = new DoStuffSimultaneously();

            // Call our method, passing in the data we want it to work on in parallel.

            string stringsAppendedInMulitpleThreads = doit.DoStuff(new string[] { "one ", "two ", "three " });

 

            // Spit out the results

            Console.WriteLine(stringsAppendedInMulitpleThreads);

        }

    }

 

    class DoStuffSimultaneously

    {

        string _response = string.Empty; // Common object the threads update with their work.

        AutoResetEvent[] _waitAllEvents; // Array of objects to wait upon.

 

        /// <summary>

        /// This method takes in a set of work and calls multiple threads for each unit of work.

        /// </summary>

        /// <param name="whatToDo">An array of strings to be appended together, each by a different thread.</param>

        /// <returns>The result of all the multiple threads' work.</returns>

        public string DoStuff(string[] whatToDo)

        {

            // Create an array of objects to wait upon; we need one per thread

            _waitAllEvents = new AutoResetEvent[whatToDo.Count];

            

            // Populate array of waiting objects, one for each work item

            for (int i = 0; i < whatToDo.Count; i++)

             _waitAllEvents[i] = new AutoResetEvent(false);

 

            // Create callback on the method we want to do the work

            WaitCallback callBack = new WaitCallback(CallSlowWebServiceInNewThread);

 

            // Iterate through all our work items, creating a thread for each and passing in the data

            // we want the thread to work on and the event we are waiting on as a state object (a Pair in this example - could be any object)

            for(int i=0; i < whatToDo.Count; i++)

                ThreadPool.QueueUserWorkItem(callBack, new Pair(whatToDo[i], _waitAllEvents[i]));

 

            // Wait until all our threads have signaled their wait object is done.

            if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)

            {

                // WaitAll for multiple handles on an STA thread is not supported.

                // ...so wait on each handle individually.

                foreach (WaitHandle myWaitHandle in _waitAllEvents)

                    WaitHandle.WaitAny(new WaitHandle[] { myWaitHandle });

            }

            else

            {

                WaitHandle.WaitAll(_waitAllEvents);

            }

 

            // When we get here then all our threads have done their work, so we can return our result object.

            return _response;

        }

        /// <summary>

        /// This method calls our slow web service does some work in a separate thread.

        /// </summary>

        /// <param name="state">A Pair object containing a string as the work item, and a AutoResetEvent to set when we are done.</param>

        static void CallSlowWebServiceInNewThread(object state)

        {

            // Get the work for this thread out of the pair

            Pair pair = state as Pair;

 

            // Get an instance of our Slow Web Service

            Slow slowWebservice = new Slow();

 

            // Call slow Web Service using our work item (be careful of race conditions here; so lock work item)

            lock (_response)

            {

                // Get something from our Slow WebService

                _response += slowWebservice.DoSomething(pair.First);

            }

           

            // Get our wait item out of the pair

            AutoResetEvent autoResetEvent = pair.Second as AutoResetEvent;

 

            // Set our wait item to indicate we are done here.

            autoResetEvent.Set();

        }

    }

}

 

Finally, if your code is in the Data Layer and you’re calling directly against SQL Server with a bunch of slow queries then you can use something like the code example below to have SQL Server work on them simultaneously and tell us when it’s done with them.

 

using System.Threading;

 

namespace Chevron.UpstreamArchitecture.Services.Whatever

{

    class ExecSimultAsyncSqlStatementWaitAll

    {

        // Command-line app to demo launching loads of *simultaneous* SQL commands and

  // waiting for them all to come back, where we can deal with all them in one loop.

  static void Main(string[] args)

        {

            // Note "Asynchronous Processing=true" at the end of the connection string...

            string sqlConnectString = "Data Source=whatever;Integrated Security=SSPI;" +

                "Initial Catalog=whatever;Asynchronous Processing=true";

 

            // This is just used to make SQL Server wait a random few seconds to simulate a long query

            Random rnd = new Random((int)DateTime.Now.Ticks);

 

            // Create an array of SQL commands with "n" members to simulate a batch of work to do

            int n = 10;

            SqlConnection[] connection = new SqlConnection[n];

            SqlCommand[] command = new SqlCommand[n];

            string[] sqlSelect = new string[n];

            IAsyncResult[] asyncResult = new IAsyncResult[n];

            WaitHandle[] _waitAllEvents = new WaitHandle[n]; // This object is what we use to wait on the batch

 

            // Kick off 10 select statements that will run simultaneously; we DON'T wait for each one here

            for (int i = 0; i < n; i++)

            {

                // In this example, each command actually just waits for between 1 and 10 random seconds

                // In reality this could just be a slow query.

                sqlSelect[i] = "WAITFOR DELAY '00:00:" + rnd.Next(1, 10) + "';";

 

                connection[i] = new SqlConnection(sqlConnectString);

                connection[i].Open();

                command[i] = new SqlCommand(sqlSelect[i], connection[i]);

 

                // Kick off a call to SQL Server; it will return *instantly* with an object we can wait upon

                asyncResult[i] = command[i].BeginExecuteNonQuery();

 

                Console.WriteLine("[{0}] Command {1} started: {2}", DateTime.Now, i, sqlSelect[i]);

 

                // capture something to wait on for this command

                wh[i] = asyncResult[i].AsyncWaitHandle;

            }

 

            // Wait for all processes to complete and output results

            if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)

            {

                // WaitAll for multiple handles on an STA thread is not supported.

                // ...so wait on each handle individually.

                foreach (WaitHandle myWaitHandle in _waitAllEvents)

                    WaitHandle.WaitAny(new WaitHandle[] { myWaitHandle });

            }

            else

            {

                WaitHandle.WaitAll(_waitAllEvents);

                           }

 

            for (int i = 0; i < wh.Length; i++)

            {

                int recAff = command[i].EndExecuteNonQuery(asyncResult[i]); // Get back the results of each query

                Console.WriteLine("[{0}] Command {1} completed, records affected = {2}", DateTime.Now, i, recAff);

                connection[i].Close();

            }

 

            Console.WriteLine("\nPress any key to continue.");

            Console.ReadKey();

        }

    }

}

 

Posted Wednesday, October 15, 2008 1:52 PM by adamhems | 1 Comments

Terrarium is back!

"Terrarium" is a project Microsoft created with .NET 1.0 that allowed devs to write a bug or plant and have it live, fight and eat in a little digital world called Terrarium. This world connected to other instances running on other folks PC's and your bug could crawl between them and live on, even reproduce, in other people instances of Terrarium and thrive or become food for another dev's creature that was better at survival than yours. Survival of the best-programmed! You couldn't change anything about the world but you had quite a lot of creative freedom in creating your bug (or plant - not that the plants did a lot!) They could communicate and even pass on genetic traits to thier children. It was cool.

Well it went away, which is a shame; but recently was revived! Check it out!!

http://weblogs.asp.net/bsimser/archive/2008/07/16/reintroducing-terrarium-now-with-2-0-goodness.aspx

Now for the really hard part... What to call my first critter...

Posted Monday, September 08, 2008 10:00 AM by adamhems | 0 Comments

Distributed Caching in .NET

Saw this today and thought this intesting:

 http://msdn.microsoft.com/en-us/library/cc645013.aspx

Bits and a sample are available:

http://msdn.microsoft.com/en-us/data/cc655792.aspx

Until now the only caching option from Microsoft has been the Caching block from the P&P group. This offering (code named "Velocity") really ups the ante...

Posted Tuesday, June 10, 2008 1:23 PM by adamhems | 0 Comments

Aspiring Architects Webcasts this Month

I saw these Webcasts coming up this month and think they might be of interest to a lot of folks (all times are Eastern time):

·         June 16th, 2008 – 12:00 p.m. to 1:00 p.m. – Introduction to the aspiring architect Web Cast series

http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032380836

·         June 17th, 2008 – 12:00 p.m. to 1:00 p.m. – Services Oriented Architecture and Enterprise Service Bus – Beyond the hype

http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032380838

·         June 18th, 2008 – 12:00 p.m. to 1:00 p.m. – TOGAF and Zachman, a real-world perspective

http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032380840

·         June 23rd , 2008 – 12:00 p.m. to 1:00 p.m. – Realizing dynamic systems

http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032380846

·         June 24th, 2008 – 12:00 p.m. to 1:00 p.m. – Web 2.0, beyond the hype

http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032380848

·         June 25th, 2008 – 12:00 p.m. to 1:00 p.m. – Architecting for the user experience

http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032380850

·         June 26th, 2008 – 12:00 p.m. to 1:00 p.m. – Conclusion and next steps

http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032380852

 

Posted Friday, June 06, 2008 12:18 PM by adamhems | 0 Comments

.NET: What's coming down the Pike

Today there a bunch of new bits to play with that have up until now been a collection of individual CTP's - yes it's the first beta of Visual Studio 2008 and .NET Framework 3.5 Service Pack 1! This is more interesting than many betas as there a lot of new stuff in this Service Pack, not just bug fixes; including all of my most-anticipated new features:

  • ASP.NET Data Scaffolding Support (ASP.NET Dynamic Data) - this is not dissimilar to Ruby On Rails in that it gets you to a web site in front of a database very quickly (and with minimal, possibly no, code) - really cool
  • ADO.NET Entity Framework (and LINQ to Entities) - basically a very powerful, flexible ORM which, among other things, supports inheritance! Entities can be used in WCF, too. This is my favourite new feature :-)
  • ADO.NET Data Services (was called "Astoria"): This is basically REST-based data services (including a LINQ Client that queries them); when used with the Entity Framework (optional, but cool) you can very quickly publish a really simple to use yet powerful API directly to your data schema - so cool (my second favourite new feature!)

These three alone will save a ton of code... I can't wait!! To learn more and see all the other stuff included in this Service Pack coming your way soon, be sure to read this.

Posted Monday, May 12, 2008 3:21 PM by adamhems | 0 Comments

Enterprise Library and WCF

If you're creating Web Services using WCF (or ASMX, for that matter) then you are, of course, using the Web Service Software Factory to create them (right?). Well one thing the WSSF does not include is the hooks to the various blocks within the Enterprise Library that many would find useful in tier freshly-generated Web Services; like Validation, Exception Handling and Logging, Performance Counters, Caching and Exception Shielding. These have to be manually added after you've generated your code.

Well recently a team from Avenade decided to fix this problem and have released to CodePlex an extension to the WSSF called the "EntLib Extensions To WSSF". Once installed (a matter of copying the dll's and updated configuration XML in the appropriate place) you get an additional option when choosing the implementation technology - "WCF with Entlib". Choosing this exposes a slew of new options within your Model that permits you to add all the logging, caching etc. hooks you like; you just need to use the EntLib Configuration tool on your finished Solution (just as you ordinarily would) in order to Make It Work, which is a lot simpler :-)

Posted Monday, May 12, 2008 8:32 AM by adamhems | 0 Comments

An easier way to Create SharePoint Feature Solutions

If you're developing Features for SharePoint then you will have discovered what a laborious process it is getting from the compiled dll, Feature.xml etc in Visual Studio to a deployed Feature in your SharePoint Dev environment. The least painful way I have of doing this so far is to make sure the directory structure of my solution matches that of the SharePoint Root Files directory, and then to use a batch file called after successful compilation that GAC's the dll, XCopy's the files in my feature to the SharePoint directory, and optionally builds the .wsp. This works but is still quite painful.

A colleague pointed me to a proof-of-concept by renowned SharePoint guru and Microsoft MVP Tedd Pattison called STSDEV on codeplex. (I've been to two of Ted's SharePoint classes - this one and this one - and I can't recommend them highly enough.) The tool he created simplifies this process even more by providing a tool you can install and call from the VS2005/8 "Tools" menu that prompts you to create one of a variety of Solution types - like Feature Solution, Web Part solution, etc. - in VS2005 or VS2008. The solution generated sets everything up for you and includes build targets (i.e. alternatives to the default "Debug" and "Release") that will build the solution, make the wsp, and install it on the SharePoint server! So the same end result is achieved but with a lot less batch files. If you do any SharePoint development, this tool is well worth a look.

Posted Friday, February 22, 2008 8:09 AM by adamhems | 1 Comments

Entity Framework beta 3 Released
If you like tools that make creating your data layers easier (like NHibernate or code generation tools like Codesmith & NetTiers), you might be interested in the latest release from the ADO.NET team - the Entity Framework (EF). The latest release, announced today, now also supports Visual Studio 2008 RTM and together with a modeling tool  allows you to quickly construct a high-performance, disconnected data layer for your applications; a major time saver for this perennial chore.

Posted Thursday, December 06, 2007 12:31 PM by adamhems | 2 Comments

Interesting Discovery: a *book* on the CAB & SCSF!

I learned today that there was a book published a few months ago on two of my favourite technologies, the Composite UI Application Block (CAB) and the Smart Client Software Factory (SCSF):

 Programming Microsoft Composite UI Application Block and Smart Client Software Factory

If you're not familiar with the CAB, and you write moderately+ complex WinForms applications, then you're going to want to take a look as it provides a basis for making your life much easier; especially if you are sharing the work with other developers. The SCSF automates much of the work of creating the CAB project in the first place using Visual Studio so once you've come to understand CAB then you're going to want to take a look at that, too.

Having a book available to help learn this stuff is going to be a great help to those new to this technology as the learning curve, though not very long, is pretty darn steep so I recommend new users pick up a copy of this book to ease them up it.

The future for the CAB looks bright, too; work has commenced on updating it for leveraging WPF and it will be called the WPF Composite Client. This builds upon the work done by a very cool project I've blogged about before called Acropolis which itself builds upon the CAB, taking all the best practices and baking them into Visual Studio. They recently announced they were calling a halt on Acroplis in favour of the WPF Composite Client so the latter is definitely an important one to keep an eye on if you're a WinForms developer.

Posted Wednesday, October 31, 2007 8:08 AM by adamhems | 0 Comments

Progammatically Adding Folders to a SharePoint List

This took me longer than it should have to get working as the things I tried first compiled but did nothing:

 myList.Folders.Add("DoesNotWork", SPFileSystemObjectType.Folder);

The way I got it to work in the end was like this: 

            SPList myList = myWeb.Lists["My List"];
            SPListItem newFolder = myList.Items.Add(myList.RootFolder.ServerRelativeUrl, SPFileSystemObjectType.Folder, null);
            if (newFolder != null)
            {
                newFolder["Name"] = "Name of Folder";
                newFolder.Update();
            }

Hope this helps somebody :-)

Posted Thursday, August 30, 2007 12:19 PM by adamhems | 1 Comments

Updated MOSS SDK

If you're a MOSS guy like me then you'll know all about the MOSS Software Development Kit - and how it could really use.. erm... filling out :-)

Well an updated version of it has just been released (download it here or see it online here), along with one for SharePoint 3.0 too (download it here or see it online here).

Posted Thursday, August 23, 2007 8:37 AM by adamhems | 0 Comments

The Repository Factory

As you might know, the Web Service Software Factory includes a Data Access Guidance Package that can generate sprocs, entities and data access components from a database schema - great if, like me, you hate typing all this boring code yourself when you need a nice Data Access Layer to talk to your Database.

Well this functionality was deemed important enough to warrant it's own project, and so now we have The Repository Factory. Worth keeping an eye on!

Posted Wednesday, August 22, 2007 4:57 PM by adamhems | 1 Comments

Making and reading ZIP Files in .NET

So you want to use the zip file format in your .NET 2/3/3.5 application? There is a compression namespace in .NET 2.0, of course; but it doesn't do zip, only deflate and GZIP (so you can't have multiple files in one archive).

So to date I've always used the venerable SharpZipLib, written for .NET 1.1 but which still converts cleanly to newer versions and does the job.

Well what I found out today is that there is actually an example in the Windows Vista SDK! When it's installed in the default location you will find it in a zip file called "Framework Samples" in C:\Program Files\Microsoft SDKs\Windows\v6.0\Samples; within that zip file there is a folder called Applications\CompressionSample and it is available in both C# and VB.NET.

There are a couple of limitations that I know of; namely it won't compress files that are already compressed very well (and may end up making them larger); and it won't compress files larger than 4Gb. (Tell me if you know of any others...) For a better experience, you'll need to buy a component from a third party. :-)

Posted Friday, August 10, 2007 9:17 AM by adamhems | 0 Comments

More Acropolis Goodness
If you're testing out all the new features of VS 2008 (now in beta 2) then you might want to play with the latest CTP of Acropolis, which is the next version of the Composite UI Application Block (CAB), which if you're a WinForms developer you are hopefully already using to save you a lot of grief on those larger projects. Acropolis integrates the CAB into the Development Environment, and adds full-blown WPF support for your SmartParts. If you're a WinForms (or "Smart Client") developer, you should definitely take a look!

Posted Wednesday, August 08, 2007 10:20 PM by adamhems | 0 Comments

Learning ASP.NET & WCF by Example: .NET Trader

If you're like me, then you like figuring out how something is supposed to be done by looking at a really good example.

Complete, full-blown, high-performance ASP.NET Enterprise Client-Server Application examples are rather few and far between. In fact I think for many people, the first one they've really seen the insides of is the first one they built; that was certainly my experience.

Help is at hand in the form of the .NET Trader application. This is actually a .NET version of an application created by IBM to showcase their WebSphere product but that's not what I find interesting; it's how it was built that is of value to us dev's and you can download and examine all the source code from here:

 http://msdn2.microsoft.com/en-us/netframework/bb499684.aspx

Well worth the time to check out how it works even if you know how you would do it; it's pretty interesting stuff!

Posted Tuesday, August 07, 2007 8:32 AM by adamhems | 0 Comments

More Posts Next page »
 
© 2008 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Page view tracker