Wednesday, April 30, 2008

SiteMapResolve and dynamic site map paths

One of the issues I faced recently was to build a dynamic site map path for given page. At first this seems like a piece of cake, the MSDN contains an article regarding the SiteMapResolve event which is perfectly suited for this task.

Alas, this would be too simple. Do you see why the MSDN example is completely broken and will not work at all?

Well, the answer is here:

private void Page_Load(object sender, EventArgs e)
{
    // The ExpandForumPaths method is called to handle
    // the SiteMapResolve event.
    SiteMap.SiteMapResolve +=
      new SiteMapResolveEventHandler(this.ExpandForumPaths);
}

You see, the SiteMapResolve is a static event which means that every time the page is loaded it will add yet another handler for this event! After few thousands of requests, few thousands instances of the same handler will be attached to the the event! And guess what? Since all handlers return a value and the event expects a single value, the value from the handler which was attached as the first one will always be returned.


A complete disaster!


There's one way to overcome this mess - you have to attach an event and then unattach it. This approach is described in the CodeProject's A Better SiteMapResolve article.


However, I think that this approach has two major disadvantages:



  • your page has to inherit from specific BasePage class

  • even though handlers are attached and then unattached, threading issues still can occur since it is possible that for a period of time more than one handler is attached to the event

How to solve this issue then once and for all?


Well, let's have a single event handler, attached once in the Application.Start event. Then, when the handler fires, we'll check whether current handler (page) implements our specific interface and if this is so, we'll redirect the execution to the handler.


Let's start with the definition of the interface:



public interface ISiteMapResolver
{
    SiteMapNode SiteMapResolve( object sender, SiteMapResolveEventArgs e );
}

Let's also modify the GlobalApplication class to add a single handler for the SiteMapResolve:



public class GlobalApplication : System.Web.HttpApplication
 {
     protected void Application_Start( object sender, EventArgs e )
     {
         /* SiteMap resolve */
         SiteMap.SiteMapResolve += new SiteMapResolveEventHandler( Provider_SiteMapResolve );
     }
 
     SiteMapNode Provider_SiteMapResolve( object sender, SiteMapResolveEventArgs e )
     {
         if ( e.Context.CurrentHandler is ISiteMapResolver )
             return ( (ISiteMapResolver)e.Context.CurrentHandler ).SiteMapResolve( sender, e );
         else
             return null;
     }
 
     ...

and then let's implement the interface on a specific page:



public partial class TheSpecificPage : Page, ISiteMapResolver
{
 ...
 
 public SiteMapNode SiteMapResolve( object sender, SiteMapResolveEventArgs e )
 {
     // build a dynamic, page specific site map path to show it 
     // in the SiteMapPath control
     SiteMapNode parent = new SiteMapNode( e.Provider, "1", "~/TheStartPage.aspx", "Start page" );
     SiteMapNode child  = new SiteMapNode( e.Provider, "2", "~/TheSpecificPage.aspx", "Specific page" );
     child.ParentNode = parent;
 
     return child;
 }
}
That's should be it. We've observed no threading or any other issues. Please share your experiences on this approach.

Tuesday, April 15, 2008

C# code snippets for lists

How many times do you enumerate your collections to perform some operations? How many times do you use following idiom?

List<T> list;
...
 
foreach ( T t in list )
{
  // do something with t
}

Isn't it boring?


It seems that the List<T> has a rather rarely used method, ForEach which can be used instead of C#'s foreach:



list.ForEach( t => // do something with t )

This looks especially refreshing when used for loops that initialize containers. Compare the usual version:



class Model {
  public List<Entity> Entities;
 
  public Model( int EntityCount ) {
    Entities = new List<Entity>();
 
    // usual container initialization rountine
    for ( int i=0; i<EntityCount; i++ ) {
      Entities.Add( new Entity() );
    }
  }
}


with the new one:


class Model {
  public List<Entity> Entities;
  
  public Model( int EntityCount ) {
    Entities = new List<Entity>();
 
    Enumerable
      .Range( 0, EntityCount )
      .ToList()
      .ForEach(
         i => Entities.Add( new Entity() )
      );
  }
}

Note that the for instruction is missing and instead Enumerable.Range with ForEach is used to get the same result.


One could surely argue if this new version is more readable but compare this one:



Model m = new Model();
 
foreach ( Entity e in m.Entities )
    foreach ( Subentity s in e.Subentities )
    {
         // do something with s
    }

and this one:



Model m = new Model();
 
m.Entities.ForEach( e => e.Subentities.ForEach( s => // do something with s ) );

Yet another interesting but rarely used pattern arises when literal representations of list items must be merged together to form a literal representation of the list. I often see something like that:



List<T> list;
...
 
StringBuilder sb = new StringBuilder();
foreach ( T t in list ) {
  sb.AppendFormat( "{0}, ", t );
}
// remove ending ", "
if ( sb.Length > 2 )
  sb.Remove( sb.Length - 2 );

while string.Join should be used to get the same result with much cleaner code:



List<T> list;
 
// first convert List<T> to List<string> using ConvertAll
// then convert List<string> to string[] expected by the string.Join
string result = 
  string.Join( ", ", list.ConvertAll( t => t.ToString() ).ToArray() );
Happy coding!