Sunday, May 23, 2010

Handling the AggregateException

Last week I showed you how you can use the AggregateException to apply consistent exception handling in batch operations. You can find that post here.

Bart De Smet read that post and pointed out that I should check out the Handle method of the AggregateException.

The Handle method

As found in the MSDN documentation.

Invokes a handler on each Exception contained by this AggregateException.

System.Func<Exception, Boolean> predicate
The predicate to execute for each exception. The predicate accepts as an argument the Exception to be processed and returns a Boolean to indicate whether the exception was handled.

Each invocation of the predicate returns true or false to indicate whether the Exception was handled. After all invocations, if any exceptions went unhandled, all unhandled exceptions will be put into a new AggregateException which will be thrown. Otherwise, the Handle method simply returns. If any invocations of the predicate throws an exception, it will halt the processing of any more exceptions and immediately propagate the thrown exception as-is.

In practice

I refactored the example in my previous post to make use of the Handle method.

   1:  static void Main(string[] args)
   2:  {
   3:       try
   4:       {
   5:            ExecuteBatch();
   6:       }
   7:       catch (AggregateException aggEx)
   8:       {
   9:            aggEx.Handle(HandleBatchExceptions);
  10:       }
  12:       Console.ReadLine();
  13:  }

I'm passing a Func<T, TResult> delegate to the Handle method. In this delegate I decide whether I'm handling the exception or not. If I handle the exception, I return true, else I return false.

   1:  private static bool HandleBatchExceptions(Exception exceptionToHandle)
   2:  {
   3:       if (exceptionToHandle is ArgumentNullException)
   4:       {
   5:            //I'm handling the ArgumentNullException.
   6:            Console.WriteLine("Handling the ArgumentNullException.");
   7:            //I handled this Exception, return true.
   8:            return true;
   9:       }
  10:       else
  11:       {
  12:            //I'm only handling ArgumentNullExceptions.
  13:            Console.WriteLine(string.Format("I'm not handling the {0}.", exceptionToHandle.GetType()));
  14:            //I didn't handle this Exception, return false.
  15:            return false;
  16:       }          
  17:  }

When we run this example a new AggregateException is thrown with the exceptions I didn't handle.


Make use of the Handle method to run over each InnerException and decide which exception you want to handle or not. The exceptions you didn't handle are automatically wrapped in a new AggregateException which gets rethrown.

Wednesday, May 19, 2010

Fixed commenting

After giving my blog a new design a few people pointed out that posting a comment was broken. You had to tab your way to the submit button.

Turns out that the comment section is hosted in an iFrame and that scrolling was disabled.

That issue should be solved now. Please let me know if commenting isn't working for you!

Saturday, May 15, 2010

Exception handling in batch operations with the AggregateException

Doing batch operations and elegantly handling exceptions is a problem which every developer has faced before. In .NET 3.5 or older there is no out-of-the-box solution to handle exceptions in these types of scenarios, without being inconsistent to the normal flow of exception handling. .NET 4 introduces the AggregateException; an exception representing multiple exceptions. The AggregateException was introduced in the first place to be used with the parallel framework, but it can be used in other scenarios as well, such as batch operations.

Take a look at the following example..

I have a single action which I want to peform in batch. This single action might throw some exceptions.

   1:  private static void ExecuteSingleAction(int i)
   2:  {
   3:       if (i == 5)            
   4:            throw new ArgumentNullException("You forgot an argument.");            
   5:       if (i == 18)
   6:            throw new ArgumentException("This argument doesn't make sense.");              
   7:  }

Most of the exceptions the single action might throw shouldn't break my whole batch operation. While I'm executing the single actions I catch the exceptions which shouldn't break the batch operation and hold them in a list of exceptions. The AggregateException has a public constructor taking an IEnumerable of exceptions. If I catch some exceptions while executing the single action I throw an AggregateException passing in that list of exceptions to its constructor.

   1:  private static void ExecuteBatch()
   2:  {
   3:       List<Exception> exceptions = new List<Exception>();
   5:       for (int i = 0; i < 100; i++)
   6:       {
   7:            try
   8:            {
   9:                 ExecuteSingleAction(i);
  10:            }
  11:            catch (ArgumentNullException nullRefEx)
  12:            {
  13:                 exceptions.Add(nullRefEx);
  14:            }
  15:            catch (ArgumentException argumentEx)
  16:            {
  17:                 exceptions.Add(argumentEx);
  18:            }             
  19:        }
  21:        if (exceptions.Count > 0)           
  22:             throw new AggregateException(exceptions);            
  23:   }

In the front-end I can catch the AggregateException, run over its InnerExceptions and act based on the type of exception.

   1:  static void Main(string[] args)
   2:  {
   3:       try
   4:       {
   5:            ExecuteBatch();
   6:       }
   7:       catch (AggregateException aggEx)
   8:       {
   9:            foreach(Exception ex in aggEx.InnerExceptions)
  10:            {                  
  11:                 Console.WriteLine(ex.Message);
  13:                 if (ex is ArgumentNullException)
  14:                 {
  15:                      //Do something
  16:                 }
  17:                 if (ex is ArgumentException)
  18:                 {
  19:                     //Do something else
  20:                 }
  21:              }
  22:       }
  24:       Console.ReadLine();
  25:  }

The result looks like this.

More scenario's?

Can you imagine other scenarios where the AggregateException might be able to add some value?

Related post: Handling the AggregateException

Monday, May 10, 2010

Doing the groceries in parallel

I've started reading the excellent paper "Patterns for Parallel Programming: Understanding and Applying Parallel Patterns with the .NET Framework 4".

There is a section in this whitepaper which explains perfectly why parallel programming was and still is such an interesting problem.
Consider an analogy: shopping with some friends at a grocery store. You come into the store with a grocery list, and you rip the list into one piece per friend, such that every friend is responsible for retrieving the elements on his or her list. If the amount of time required to retrieve the elements on each list is approximately the same as on every other list, you’ve done a good job of partitioning the work amongst your team, and will likely find that your time at the store is significantly less than if you had done all of the shopping yourself. But now suppose that each list is not well balanced, with all of the items on one friend’s list spread out over the entire store, while all of the items on another friend’s list are concentrated in the same aisle. You could address this inequity by assigning out one element at a time. Every time a friend retrieves a food item, he or she brings it back to you at the front of the store and determines in conjunction with you which food item to retrieve next. If a particular food item takes a particularly long time to retrieve, such as ordering a custom cut piece of meat at the deli counter, the overhead of having to go back and forth between you and the merchandise may be negligible. For simply retrieving a can from a shelf, however, the overhead of those trips can be dominant, especially if multiple items to be retrieved from a shelf were near each other and could have all been retrieved in the same trip with minimal additional time. You could spend so much time (relatively) parceling out work to your friends and determining what each should buy next that it would be faster for you to just grab all of the food items in your list yourself.

Of course, we don’t need to pick one extreme or the other. There are dozens of variations on these two extremes. Think about how hard it must be to come up with an algorithm which always takes the most efficient path for any given scenario.

Food for thought..

Saturday, May 8, 2010

Blog redesign

Today I finally took the time to redesign my blog.

The word redesign might be a bit exaggerated though. I downloaded the 2plus blogger template and tweaked it a little. Hope you like the new design!


..and after

Your opinion

As always, I would like to hear your opinion!

Sunday, May 2, 2010

Build your own Bing image search with the Bing API and jQuery

One of the most popular parts of Bing is its image search with its never-ending scroll feature. In this post I'll show you my own implementation of a Bing-like image search using the Bing API and jQuery.

The Bing API

If you missed it, in March I did a series on the Bing API. Use this post to get started!

jQuery and the EndlessScroll plugin

There are two libraries I used: jQuery and the EndlessScroll plugin. I downloaded the EndlessScroll plugin here. Documentation can be found here.


You can download the source here. The implementation can also be found below.

   1:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "">
   2:  <html xmlns="">
   3:      <head>
   4:          <title>Bing Image Search with jQuery and the Bing API</title>
   5:          <style type="text/css">
   6:              td { padding: 20px 20px 20px 20px }
   8:              #Query { font-size: 16pt }
   9:              #Search    { font-size: 16pt }        
  10:          </style>
  11:          <script type="text/javascript" src=""></script>
  12:          <script type="text/javascript" src="scripts/jQuery_EndlessScroll.js"></script>
  13:          <script type="text/javascript">                
  14:              //The offset indicates how far into the Bing API result set we are processing.
  15:              //We need this variable to be global so we can maintain the state of the offset between Bing API calls.
  16:              var _offset;                                       
  18:              $(document).ready(function(){
  19:                  //Hook up an onclick eventhandler to the Search button.
  20:                  $("#Search").click(StartSearching);
  21:              });                
  23:              function StartSearching() {    
  24:                  //Clear the previous results from the Results table.
  25:                  ClearResults();
  27:                  //Reset the offset.
  28:                  ResetOffset();
  30:                  //Get the value from the Query textbox.
  31:                  query = $("#Query").val();
  33:                  //Start receiving the first results and hookup endless scrolling.
  34:                  ReceiveAndShowResults(query);
  35:                  HookUpEndlessScroll(query);
  36:              }        
  38:              function ClearResults(){
  39:                  //Remove the content of the Results table.
  40:                  $("#Results").find("*").remove();
  41:              }
  43:              function ResetOffset(){                
  44:                  //Reset the offset.
  45:                  _offset = 0;
  46:              }
  48:              function HookUpEndlessScroll(query){    
  49:                  //Hookup endless scrolling.
  50:                  $(document).endlessScroll({
  51:                      fireOnce: false,
  52:                      fireDelay: false,
  53:                      loader: "Loading..",
  54:                      callback: function(){        
  55:                          //Up the offset.
  56:                          _offset += 25;
  58:                          //Show more results.
  59:                          ReceiveAndShowResults(query);
  60:                      }
  61:                   });
  62:              }
  64:              function ReceiveAndShowResults(query) {            
  65:                  //Build a new API uri.
  66:                  var bingUri = BuildBingApiUri(query, _offset);        
  68:                  //Make the API call.        
  69:                  $.ajax({
  70:                      url: bingUri,
  71:                      success: OnResultsReceived,
  72:                      error: OnError
  73:                   });           
  74:              }
  76:              function OnError(XMLHttpRequest, textStatus, errorThrown) {
  77:                  //Show an error when the API call fails.
  78:                  $("#Results").append("<tr><td>Something went wrong..</td></tr>");    
  79:                  $("#Results").append("<tr><td>" + textStatus + "</td></tr>");    
  80:              }
  82:              function OnResultsReceived(data, textStatus) {                
  83:                  //If there are no results show a message.
  84:                  if (data.SearchResponse.Image.Results == null || data.SearchResponse.Image.Results == undefined){
  85:                      $("#Results").append("<tr><td>No Results..</td></tr>");    
  86:                      return;
  87:                  }                    
  89:                  //Loop over the results and build the Results table.
  90:                  $.each(data.SearchResponse.Image.Results, function (i, item) {                                        
  91:                      switch (true){
  92:                          case i == 0:
  93:                              $("#Results").append("<tr>");                                        
  94:                              $("#Results").append("<td><img src='" + item.Thumbnail.Url + "'/></td>");
  95:                              break;
  96:                          case i == data.SearchResponse.Image.Results.length:
  97:                              $("#Results").append("<td><img src='" + item.Thumbnail.Url + "'/></td>");
  98:                              $("#Results").append("</tr>");        
  99:                              break;
 100:                          case ((i + 1) % 5) == 0:
 101:                              $("#Results").append("<td><img src='" + item.Thumbnail.Url + "'/></td>");
 102:                              $("#Results").append("</tr><tr>");        
 103:                              break;
 104:                          default:
 105:                              $("#Results").append("<td><img src='" + item.Thumbnail.Url + "'/></td>");    
 106:                              break;
 107:                      }                                
 108:                  });              
 109:              }
 111:              function BuildBingApiUri(query, offset) {
 112:                  //Build an uri for the Bing API call.                                
 113:                  var bingApiUrl = "";
 114:                  var bingApiAppId = "3465F86307063B7ADC5D16E6A608A110E437E925";
 115:                  var bingApiImageCount = "25";                
 117:                  var s = bingApiUrl +
 118:                              "?AppId=" + bingApiAppId +
 119:                              "&Sources=image" +
 120:                              "&Query=" + query +
 121:                              "&Image.Count=" + bingApiImageCount +
 122:                              "&Image.Offset=" + offset;
 124:                  return s;                
 125:              }
 126:         </script>
 127:      </head>
 128:        <body>
 129:          <div id="SearchContainer" align="center">
 130:              <input type="text" id="Query"/>
 131:              <input type="button" value="Search!" id="Search"/>                
 132:          </div>        
 133:          <table id="Results">
 134:          </table>        
 135:      </body>
 136:  </html>


I only got this to work on IE. Other browsers had problems making the cross domain API calls, although jQuery should be able to handle this on every browser. Anyone an idea? This implementation also isn't production ready. I'm pretty sure this code needs more logic handling exceptions.


Being a jQuery novice, I definitely am looking for your feedback!

Edit: Check the comments for more information on the cross domain API calls!