BLOG

Aggregating WCF Service Results Asynchronously

30 September 2009 by Stuart Cam

I had a requirement recently to call multiple WCF endpoints and aggregate the results into a single list for further processing. The logical flow was similar to the following:

Logical flow

The WCF endpoints would take a reasonable length of time to return the results, so instead of executing the service calls in series I decided to create a new thread for each service call and return the aggregated list when all methods had completed.

The major pain point in any multithreaded code is managing access to shared resources between threads. If we create a temporary list for our results and insert new items we still need to manage access across multiple threads. Unfortunately, List<T> is not thread safe for modification, so we have to manage inserts through some kind of synchronisation mechanism - luckily we can use the lock(object){} syntax.

Since there are several places in the application where we'll need to do this type of aggregation I wrote some helper classes:

public abstract class MultiThreadedHelperWithBlock<TInput, TOutput>
{
    private readonly IList<Func<TInput, TOutput>> _functions = new List<Func<TInput, TOutput>>();
    private readonly object _mutex = new object();

    protected MultiThreadedHelperWithBlock<TInput, TOutput> ASyncMethod(Func<TInput, TOutput> function)
    {
        _functions.Add(function);
        return this;
    }

    protected void RunAsyncWithLockAndBlock(TInput input, Action<TOutput> action)
    {
        if(_functions.Count == 0)
            throw new Exception("Need to define at least one function to call");

        if(_functions.Count == 1)
        {
            action(_functions[0].Invoke(input));
            return;
        }

        var events = new ManualResetEvent[_functions.Count];
        for (var i = 0; i < _functions.Count; i++)
        {
            var index = i;
            var func = _functions[index];
            events[index] = new ManualResetEvent(false);
            var bw = new BackgroundWorker
            {
                WorkerReportsProgress = false,
                WorkerSupportsCancellation = false,
            };
            bw.DoWork += (sender, args) => args.Result = func.Invoke((TInput)args.Argument);
            bw.RunWorkerCompleted += (sender, args) =>
            {
                var result = (TOutput)args.Result;
                lock (_mutex)
                {
                    action(result);
                }
                events[index].Set();
            };
            bw.RunWorkerAsync(input);
        }
        WaitHandle.WaitAll(events);
    }
}

public class MultiThreadedListCombiner<TInput, TOutput> : MultiThreadedHelperWithBlock<TInput, IEnumerable<TOutput>>
{
    public new MultiThreadedListCombiner<TInput, TOutput> ASyncMethod(Func<TInput, IEnumerable<TOutput>> function)
    {
        return base.ASyncMethod(function) as MultiThreadedListCombiner<TInput, TOutput>;
    }

    public IEnumerable<TOutput> GetResults(TInput input)
    {
        var contents = new List<TOutput>();
        RunAsyncWithLockAndBlock(input, list =>
        {
            foreach (var item in list)
            {
                contents.Add(item);
            }
        });
        return contents;
    }
}

public class MultiThreadedServiceCall<TInterface, TInput, TOutput> : MultiThreadedHelperWithBlock<TInput, TOutput>
{
    private Func<TInterface, TInput, TOutput> _functionToCall;

    public MultiThreadedServiceCall<TInterface, TInput, TOutput> AttachService(TInterface service)
    {
        return ASyncMethod(request => _functionToCall.Invoke(service, request)) as MultiThreadedServiceCall<TInterface, TInput, TOutput>;
    }

    public MultiThreadedServiceCall<TInterface, TInput, TOutput> CallMethod(Func<TInterface, TInput, TOutput> functionToCall)
    {
        if (_functionToCall != null)
            throw new ArgumentException("CallMethod() has already been defined", "functionToCall");
        _functionToCall = functionToCall;
        return this;
    }

    public IEnumerable<TOutput> GetResults(TInput input)
    {
        if (_functionToCall == null) throw new NullReferenceException("Need to define CallMethod()");
        var contents = new List<TOutput>();
        RunAsyncWithLockAndBlock(input, contents.Add);
        return contents;
    }
}

OK, so the above code looks a little daunting - generics, closures and lambda expressions everywhere, but essentially all of the hard-work (such as thread spawning and synchronisation) is handled by MultiThreadedHelperWithBlock<>. The other two classes just inherit from this to perform different tasks.

The Enterprise Integration Patterns website has an interesting case study on the Loan Broker Ecosystem. Notice how the Loan broker calls multiple recipients and aggregates the results? I thought it'd be interesting to demonstrate how the above code can be used for this type of task.

Firstly we need a service interface contract, some data transfer objects and some service implementations:

// Service Contract
public interface ILoanService
{
    LoanResponse GetResponse(LoanRequest request);
}

// Data Transfer Objects
public struct LoanRequest
{
    public double Amount;
    public double Term;
}

public struct LoanResponse
{
    public string Lender;
    public double MoneyRepayment;
}

// Service Implementations
public class MoneyBagsLender : ILoanService
{
    public LoanResponse GetResponse(LoanRequest request)
    {
        Thread.Sleep(3500);
        Console.WriteLine("MoneyBags result returned");
        var repayment = (request.Amount / request.Term) * 1.05;
        return new LoanResponse { Lender = "MoneyBags", MoneyRepayment = repayment };
    }
}

public class RegularLender : ILoanService
{
    public LoanResponse GetResponse(LoanRequest request)
    {
        Thread.Sleep(5000);
        Console.WriteLine("RegularLender result returned");
        var repayment = (request.Amount / request.Term) * 1.2;
        return new LoanResponse { Lender = "Regular", MoneyRepayment = repayment };
    }
}

public class ShrewdLender : ILoanService
{
    public LoanResponse GetResponse(LoanRequest request)
    {
        Thread.Sleep(2000);
        Console.WriteLine("ShrewdLender result returned");
        var repayment = (request.Amount / request.Term) * 1.5;
        return new LoanResponse { Lender = "Shrewd", MoneyRepayment = repayment };
    }
}

The service implementations (ShrewdLender,RegularLender and MoneyBagsLender) will simulate "busy work" by just sleeping the threads for a certain amount of time.

Let's use the MultiThreadedServiceCall<> class to call these three services and return the list of LoanResponses:

// Create the Loan Request
var loanRequest = new LoanRequest { Amount = 10000, Term = 30 };

// Return an IEnumerable<LoanResponse>
var loanResponses = new MultiThreadedServiceCall<ILoanService, LoanRequest, LoanResponse>()
			    .CallMethod((service, request) => service.GetResponse(request))
			    .AttachService(new MoneyBagsLender())
			    .AttachService(new ShrewdLender())
			    .AttachService(new RegularLender())
			    .GetResults(loanRequest)
			    .OrderByAscending(response => response.MoneyRepayment);

// Display the results
foreach (var response in loanResponses)
{
	Console.WriteLine("Monthly repayment with lender '{0}' =  ${1}", response.Lender, response.MoneyRepayment);
}

This gives us the following output - the results take some time to be returned, but as soon as they are all completed the IEnumerable becomes available for further processing:

Console Output

Some Notes:

  • No error checking!
  • There may be some performance implications using the BackgroundWorker class to spawn threads - ideally we'd want to use a ThreadPool.
  • Each thread can support up to 64 WaitHandles (ManualResetEvents are built on these), although if you need to call more than 64 services you've probably got severe architectural issues.
  • .CallMethod((service, request) => service.GetResponse(request)) instructs the class to call the function GetResponse(LoanRequest request) on each service.
  • The input and output types are strongly typed by the generic type arguments.
  • .GetResults(loanRequest) returns an IEnumerable, so we are able to method chain LINQ queries.

The 3 type arguments to MultiThreadedServiceCall<> specify:

  1. The interface that each service implements.
  2. The input argument type for the specified method in .CallMethod(...).
  3. The output argument type for the specified method in .CallMethod(...).

Download the Program.cs (6.37 kb)

Tags: , , ,

Categories: .NET | C Sharp

My Current C# Development Stack

07 July 2009 by Stuart Cam

I have been fan boy of the ALT.NET movement for quite some time. I attended a few of the Sydney ALT.NET meetings when they first started and I have to say that they were remarkably more engaging than the Sydney Dot Net User Group (SDNUG). I'd like to extend a thank you to Richard Banks for starting the meetings, I really enjoyed them. If you are in Sydney I recommend you check them out and join the LinkedIn group.

I will be moving back to Bristol, UK on the 10th July 2009 and I am really pleased to hear that an ALT.NET Bristol group is starting up. Socialising, beers and geekery - a perfect combination! If you are interested then don't forget to join the ALT.NET Bristol LinkedIn Group as well.

I have tried to look outside of Redmond for .NET solutions to common problems, despite the fact that the framework is owned and developed by Microsoft. It would be fair to say that the .NET framework has attracted a lot of interest from some very smart software developers who have collaborated to create viable alternatives to Microsoft offerings. The best part is that they are usually free, well supported and open source.

  • Visual Source Safe? I'll take Subversion, thanks anyway.
  • MSTest? I'll take NUnit, thanks anyway.
  • Team System? I'll take CruiseControl, thanks anyway.
  • MSBuild? I'll take NAnt, thanks anyway.
  • ...the list goes on

My current (preferred) development stack looks something like:

If you are a .NET developer staring at the list above and thinking to yourself "what on earth is this guy talking about", I'd suggest that you check the fizzy liquid in your glass isn't Microsoft Kool Aid and visit some of the links!

Tags: , , ,

Categories: .NET | C Sharp | jQuery

I Read... There... I Said It!

03 July 2009 by Stuart Cam

I am sometimes asked "so how do you keep up-to-date with all that's happening in the industry?".

Well, I...

The problem is making time for these endeavours. Usually I will alternate between them, much like a buffet, occasionally gorging on a particular topic when I am in the right frame of mind. Obsessive? possibly... but I think it's important to have a varied diet to keep it exciting.

Online articles and coding websites are great for picking up the odd skill or two but they often lack the depth required for some topics.

I had attempted to reconcile my love of technical books and mitigate some of their downsides (size, weight, cost and errata) by purchasing a Sony PRS-500 and seeking out digital versions of titles. I bought the unit when it first launched a couple of years ago and since then it has seen relatively little action. It's been quite a disappointment. The main problem is screen size, or lack thereof. It's way too small to render diagrams and code snippets with clarity. If your primary goal is to read technical books then I'd suggest avoiding the unit altogether and consider a tablet PC instead. That, or take a look at the much larger 9.7" Kindle DX.

I have recently purchased a round of new books in dead-tree format, which I intend to read over the coming weeks...

Software Development

97 Things Every Software Architect Should Know - Various

97 Things Every Software Architect Should Know - Various

I originally found out about the book through Udi Dahan's blog. Udi has made a couple of article contributions and figured it would be worth a read since I respect his opinions on software development and admire his NServiceBus framework.

The book contains small snippets of non-technical advice from a variety of architects - experience which, in some cases, has been hard won.

The unedited contributions from each author are available for free.


SOA in Practice: The Art of Distributed System Design - Nicolai M. Josuttis

SOA in Practice: The Art of Distributed System Design - Nicolai M. Josuttis

What are the two rules of distributed computing?

1. Do not distribute, it's difficult
2. See #1 (asynchronously)

I know, I know, it's a terrible joke! I had been looking around for an authoritative book on SOA and distributed systems and this book came highly recommended for cutting through the hype. The accompanying website can be found here.


.NET Framework

Effective C#: 50 Specific Ways to Improve Your C# - Bill Wagner

Effective C#: 50 Specific Ways to Improve Your C# - Bill Wagner

I had originally found out about this book through my professional network on LinkedIn via Chris Fulstow. He had mentioned that he was reading the book so I figured it must be worth a look.

It's full of best practices specifically for C#, covering some of the more esoteric language 'features' and how to avoid digging yourself into a big hole with them.

Take a listen to the interview with Bill Wagner on .NET Rocks!


More Effective C#: 50 Specific Ways to Improve Your C# - Bill Wagner

More Effective C#: 50 Specific Ways to Improve Your C# - Bill Wagner

I figured I ought to buy the sequel as it contains information on how to get the best out of the newest C# features such as LINQ and Lambda Expressions.

I heard about this book through Chris Fulstow (again) and subsequently through another .NET Rocks! podcast with Bill Wagner.


ASP.NET MVC 1.0 Quickly - Maarten Balliauw

ASP.NET MVC 1.0 Quickly - Maarten Balliauw

I've been aware of the ASP.NET MVC framework for quite some time. Pretty much the day after Scott Guthrie announced a prototype at the ALT.NET conference. I was looking for a short book which would assume knowledge of ASP.NET and cut straight to the .NET MVC implementation.

Since v1.0 is fairly new there are numerous online tutorials for earlier versions and some great MVC blogs, but not much in the way of printed books. This looked to be the best of a small bunch.


Windows Presentation Foundation Unleashed - Adam Nathan

Windows Presentation Foundation Unleashed - Adam Nathan

I have a minor confession. I have zero WPF experience, which is a little embarrassing since it replaced GDI+ long, long ago.

Unlike many other technical books this one is printed on glossy paper in full colour and totally jam packed with pictures and diagrams. Perfect presentation for learning a presentation framework!

An ex-colleague, Jack Ukleja, recommended this book.


Other Technologies

The Definitive ANTLR Reference - Terrence Parr

The Definitive ANTLR Reference - Terrence Parr

I purchased a digital copy of this book some time ago and have nearly finished reading it... in the bath... on my PRS-500... wrapped rather optimistically in cling film. This time I figured I'd buy the paper version and risk the £16.88 it would cost me to replace if I dropped it!

Bath + electrical items != mix.


Compilers: Principles, Techniques and Tools - Various

Compilers: Principles, Techniques and Tools - Various

Probably the densest, in both physical and subject matter, of all the books I purchased. I had a quick flick through some of the material and it looks pretty heavy going and full of maths. I anticipate that this will take a long time to read and no doubt expose many other holes in my knowledge along the journey.

My primary motivation was to supplement the ANTLR book with other compiler topics.


Collective Intelligence in Action - Satnam Alag

Collective Intelligence in Action - Satnam Alag

A rather interesting book intended for a Java audience, but which contains mathematics and algorithms suitable for implementation elsewhere. I discovered the book whilst surfing the internet for recommendation engines, which itself was a spur from reading about a recommendation engine that Joel Pobar had written in F#.

Hopefully this book will shed some insight on writing a sophisticated Web 2.0 application.


NHibernate in Action - Various

NHibernate in Action - Various

Another re-purchase of a book I own in digital form. I have followed it through the Manning Early Access Program.

My main gripe is that it doesn't cover the newest version of NHibernate, but given the time it takes to write a book and the speed at which frameworks evolve it's forgivable.

One of the best references for NHibernate available today.


Other

Here Comes Everybody - Clay Shirky

Here Comes Everybody - Clay Shirky

If I had a dollar for every time I heard Jeff Atwood mention Clay Shirky on the StackOverflow podcast I'd probably be able to buy this book without opening my wallet! Instead, I decided to spend my own money and discover the material for myself.

It comes highly rated and promises some insight on the huge changes we are seeing on the internet today with social networking and the wisdom (or madness) of crowds.


The Paradox of Choice: Why More is Less - Barry Schwartz

The Paradox of Choice: Why More is Less - Barry Schwartz

This is the least technical book of the bunch, cited as a reference in The Cult of the Amateur - a book I really enjoyed reading on my travels.

I would probably consider myself a 'maximiser' when it comes to making purchases - perhaps this book will change the way I rationalise my spending decisions? Perhaps it will change the way I buy books? :)


Simply put, read books and treat your education as a #1 priority.

Bill Hicks would probably agree (just with more swearing):

Tags: , , ,

Categories: .NET | Books | C Sharp | General | MVC | SOA | Web

.NET 4.0 - The Game Changers (In My Opinion)

27 May 2009 by Stuart Cam

If you haven't yet noticed .NET 4.0 and Visual Studio 2010 are out of CTP and into Beta. Bleeding-edge developers might want to download and take them for a spin.

There are quite a few new features in .NET 4.0, the most interesting for me are:

  • Task Parallel Library (TPL). Now a first class citizen in the framework, the Parallel FX (PFX) library makes writing multithreaded code a breeze. I had the opportunity to attend a talk on the PFX library with Joe Duffy at TechEd, Sydney 2008 . It's nice to see this library finally make it into the BCL.
  • Dynamic Language Runtime (DLR). Dynamic languages, such as IronPython and IronRuby, now make 'official' status in the .NET framework. C# implements a new dynamic keyword to interop with dynamic languages. Here is a great video on Channel 9 with Eric Lippert and the C# compiler developers where they talk about C#'s static viewpoint on dynamic typing.
  • Code Contracts & Pex. Remember Spec#? the superset of C# with design-by-contract features? Well, the team in Microsoft Research have decided to bundle all of the idioms into a .NET library, welcome the new namespace System.Diagnostics.Contracts. This video at PDC 2008 gives a great overview of C# design-by-contract programming, and a wonderful demonstration of Pex. Download Code Contracts for Visual Studio 2008.

The IDE is also gradually making the transition to WPF making the whole visual experience a lot more pleasing. I wonder how far the customisation will be taken?

.NET 4.0 doesn't quite have the same impact on me (personally) that .NET 3.5 had (I am still blown away by just how powerful and brilliant LINQ is). That said it's really exciting to see Microsoft taking the framework forward and offering their take on the future of Windows programming. Take a look at how .NET is changing.

Tags: , , ,

Categories: .NET | C Sharp


© Codebrain 2017. All Rights Reserved. Registered in England: 07744920. VAT: GB 119 4078 13