Thursday, June 12, 2008

C# Puzzle No.3 (level: beginner)

Can two static variables which refer to each other cause an infinite recursion?

public class A
{
  public static int a = B.b + 1;
}

public class B
{
  public static int b = A.a + 1;
}
 
public class MainClass
{
  public static void Main()
  {
    Console.WriteLine( "A.a={0}, B.b={1}", A.a, B.b );
  }
}

Can you explain what would be the output (if any) of the above code without actually running it?

C# Puzzle No.2 (level: intermediate)

Following code snippet is commonly used in C/C++ to exchange values of two integer values with no help of any additional variable.

int x, y;
 
x ^= y ^= x ^= y;

This surprisingly does not work in C#. Can you explain why?

C# Puzzle No.1 (level: beginner)

Would you like to see a collection which magically creates an item as soon as you ask for it? Well, here it is. The collection is asked to return a value for a key, and volia, you will be informed that the item exists in the collection.

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
 
namespace ConsoleApplication
{
    class Program
    {
        static void Main( string[] args )
        {
            NameValueCollection Collection = new NameValueCollection();
 
            Console.WriteLine( 
                "Does NameValueCollection magically create items? " +
                Collection["foo"] != null ? " Yes, it does!" : "No, it doesn't." 
                );
        }
    }
}

Can you spot the problem in the code?

Wednesday, June 4, 2008

How to detect that the login page is invoked because of insufficient priviledges

The login page of the ASP.NET application using Forms authentication is invoked by the engine in two different scenarios:

  • when the user is not authenticated at all
  • when user is authenticated but has insufficient priviledges

Now suppose that you do not make any difference between these scenarios in the login page code. The user logs in and then tries to access a resctricted area, guarded with the authorization policy. Though he/she is logged in, the engine redirects the call to the login page. The user provides his/her identity but the situation repeats. This lack of the informative description of the issue could very frustrating for the user. His credentials seem unaccepted while in fact the credentials are ok but the authorization policy refuses his credentials as valid.

Luckily there's a trivial solution - in the Page_Load of the login page you just check if the Context.User.Identity.IsAuthenticated flag is true. If this is the case then it means that the user is logged in but has been redirected because of the authorization policy. You can then hide the username/password input fields and instead provide a message "The user which is currently logged in has no sufficient priviledges to access the page".

Tuesday, June 3, 2008

LINQ and synonyms / linked servers

I've been asked if it's possible to perform joins across different databases using LINQ. The first obvious answer is yes, you just do inproc join using Linq To Objects and two different contexts:

from a in new List<A>( context1.TheA )
  join b in new List<B>( context2.TheB )
    on ---

But what if you'd like to have it executed on the server side? At first I thought that it should be obvious - while you cannot refer to two different contexts, you can of course use linked servers / synonyms mechanism built into the SQL Server 2005.

 

This however turned out to be impossible - for an unknown reason, probably a bug, sqlmetal does not include synonyms in the generated model. And because VS uses internally the same mechanism used in sqlmetal, the designer is not a big help also.

 

But what if you generate the missing part of the model by hand? Well, it seems that it does the trick. You just


  • generate the model for the main database

  • generate models for databases which contain tables linked from within the main database

  • trim these generated models (usually you do not create synonyms for the WHOLE database but rather for selected tables)

  • change the namespace and the class name of all generated classes to the same names

That's it. You have a single model which spans several files generated independently but it does not matter as all files contain partial definition of the same class.


 

BTW. The lack of the on-demand synchronization between the relational database schema and the dbml definition is kind of mockery to me.

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!