August 2008 - Posts

Monorail Dynamic Actions = Reusable Goodness!

Monorail gives you a nice, easy to use MVC implementation on top of ASP.NET.  Dynamic Actions is a feature that allows code reuse across controllers without restricting you to specific inheritence model.

In classic MVC style, Monorail controllers expose actions.  Any "public void" method on a controller class is considered an action:

public void Index()
{
...
}
 
public void NotOpen()
{
...
}
 
public void OrderClosed()
{
...
}

Sometimes, you may want the same action available on multiple controllers.  Since a controller is simply a .NET class, you could use inheritence, but more often than not, that doesn't fit well into your solution.

For my example, I've got a Monorail application I wrote for my daughter's grade school.  I used the techniques described here to provide a textbox with AJAX autocomplete used to select a particular guardian (NOTE: we have to be politcally correct here as the person who is the actual guardian may not be the parent.  Hence, we use the term "Guardian").  It works great and was easy to set up.  The NVelocity template code is simply:

Find by Guardian Name (Last, First): $AjaxHelper.InputTextWithAutoCompletion("parentsName", "FindGuardians.ashx", "%{}", "%{}")

My "FindGuardians" action (method) is pretty simple too:

public void FindGuardians(string parentsName)
{
    if (parentsName.Length > 0)
    {
        Guardian[] g = Guardian.FindAllStartingWith(this.CurrentSchool, parentsName);
        PropertyBag["parents"] = g;
    }
}

The "CurrentSchool" property is on a base class from which all of my controllers derive from.  It lets all of the other controllers know what school the current user is enrolled in.  And, as you saw in the previous link, our view for "FindGuardians" that renders the autocomplete list is simple:

<ul>
#foreach($parent in $parents)
    <li>$parent.ContactInfo.LastName, $parent.ContactInfo.FirstName</li>
#end
</ul>

So the first time I needed this lookup on a different view, I just did a quick copy paste.  C'mon -- a 9-line method and a single view?  Just copy it.

Well, as time moved on, I needed this lookup in a number of different controllers.  I turned to Monorail's Dynamic Actions and Shared Views to get me some reusable goodness!

A Dynamic Action is an action that is added to the controller during initialization.  It's an action on the controller, accessible by a name, but is not one of the "public void" methods compiled with the class.  It's a class in itself that implements IDynamicAction.  When the action is called, the IDynamicAction.Execute of the dynamic action is called.

Converting the controller code to a dynamic action was pretty straightforward.  I had to deal with pulling the "parentsName" out of the request manually since I'm not going through SmartDispatcherController.  And I moved the FindGuardians view code to a shared view so it could also be accessed by the dynamic action from anywhere.  Here's the final code:

public class FindGuardiansAction : IDynamicAction
{
    #region IDynamicAction Members
 
    public object Execute(IEngineContext engineContext, IController controller, IControllerContext controllerContext)
    {
        ControllerBase baseCtlr = (ControllerBase)controller;
        string parentsName = engineContext.Request.Params["parentsName"];
 
        if (parentsName.Length > 0)
        {
            Guardian[] g = Guardian.FindAllStartingWith(baseCtlr.CurrentSchool, parentsName);
            baseCtlr.PropertyBag["parents"] = g;
        }
        baseCtlr.RenderSharedView("Shared/Lookups/FindGuardians", true);
 
        return null;
    }
 
    #endregion
}

One last thing I did was create a static method on the FindGuardiansAction class to make installation easy:

public static void InstallOn(Controller controller)
{
    controller.DynamicActions["FindGuardians"] = new FindGuardiansAction(includeStaff);
}

Now when I need the FindGuardians action on a controller, I call the InstallOn during initialization of the controller:

public override void Initialize()
{
    base.Initialize();
    FindGuardiansAction.InstallOn(this);
}

There's a couple of other AJAX autocomplete lookups I've created using these methods and it makes my life so much easier and the development is so much quicker.

Announcing Mads Torgersen as keynoter at CodeMash!

Just announced (about 45 minutes ago): Microsoft Language PM Mads Torgersen will be a keynote speaker at CodeMash!  This is great news!  I visited one of Mads' session at the MVP Summit this year and it was really good.  He's a great speaker and has an enormous amount of C# and .NET knowledge to share.

Euler 10

After tackling number 9 yesterday, I thought I'd do #10 real quick since it seemend pretty easy.

Calculate the sum of all the primes below two million.

The code for the algorithm was a simple 2 lines:

var range = GeneratePrimes().TakeWhile(x => x < 2000000);
int sum = range.Sum();

But I have to confess that I took most Bill's GeneratePrimes() from is solution to Euluer #7.  I say "most" because I didn't grok his implementation of IsPrime().  I read his description a number of times and even stepped through the code a couple of iterations, but I still didn't "get" his use of the List<int> to keep a list of already found primes.

So I wrote my own IsPrime().  I used the canonical definition of a prime number ("a number which is evenly divisible by one 1 and itself").

public static bool IsPrime(this int number)
{
    if (number == 1)
        return false;
    if (number == 2)
        return true;
 
    var range = Enumerable.Range(2, number - 2).ToList();
    return range.TrueForAll(n => number % n != 0);
}

So I started running my solution.  After about 10 minues, I paused and saw that I was still generating prime numbers in the 20,000-30,000 range.  Hmmm...  Ok, I'll just let it run overnight.

I got up about 7.5 hours after going to bed and my app was still running!  I paused it and saw it was only in the 950,000 range of determining primes below 2 million (not even half way through!).  So I decided to take 20 seconds and really THINK about my IsPrime() method and realized how inefficient it was to generate that huge range to use the 'TrueForAll' on.

So I eliminated the LINQ code and did a simple for loop that will break out as soon as it finds a number that is evenly divisible:

public static bool IsPrime(this int number)
{
    if (number == 1)
        return false;
    if (number == 2)
        return true;
 
    for (int n = 2; n < number; n++)
    {
        if (number % n == 0)
            return false;
    }
 
    return true;
}

Now I ran the code and after about 20 minutes ran into a new problem: An overflow exception calling range.Sum().  On the good side, it only took about 20 minutes to get my primes under two million.  On the bad side,  I should have thought about that line of code a little more.  Adding up all of the primes below two million is probably going to produce a huge number (much bigger than a 32-bit integer could hold).

So I decided to move the range "up" to use longs (I didn't feel like going back and changing the extension method to use longs):

var longrange = range.Cast<long>();
var sum = longrange.Sum();

Success in about 20 minutes!

PS - I went back and ripped out my IsPrime() and put Bill's back in.  Now it completes in about 5 minutes.  How come the boss is always right?

Project Euler #9

So I decided to start looking into the Project Euler problems.  A number of fellow SRT employees have been tackling these over the past few months and after recently reading Bill's solutions for problems #7 and #8 I decided to look at #9.

Find the only Pythagorean triplet, {a, b, c}, for which a + b + c = 1000.

I thought about this for quite a while.  I was trying to see how I could utilize LINQ to make this easier.  In the end, I decided to just use the brute force method of nested loops:

private static void Euler9()
{
    for (int a = 0; a < 1000; a++)
    {
        for (int b = a + 1; b < 1000; b++)
        {
            for (int c = b + 1; c < 1000; c++)
            {
                if (a + b + c == 1000 && (Math.Pow(a, 2) + Math.Pow(b, 2) == Math.Pow(c, 2)))
                {
                    Console.WriteLine("{0},{1},{2}", a, b, c);
                    return;
                }
            }
        }
    }
}

I added a few optimizations in an effort to speed this up:

  • Since a+b+c has to equal 1000, no single element (a or b or c) can be greater than 1000.  Therefore my loops are pretty short.
  • I took advantage of C#'s short-circuiting to do the simple "a + b + c == 1000" check before doing the squares.

It runs pretty quick (under a second).  The first time I ran it I took out the "return" to make sure my logic only produced a single result.  It did!  :)