Sunday, April 29, 2012

ASP.NET MVC Editor Templates

EditorTemplates reminds me of college days using assembly language. Copying bytes using MOV and LOOP instruction could get the job done, but not knowing the simpler way(REP MOVSB) to do this solved problem makes your code not as readable or maintainable as it could possibly be. Seeing many loops in code and deciphering their intent is counter-productive.


As much as we want to believe in this axiom "If At First You Don't Succeed, Remove All Evidence You Ever Tried", there's something to be said for knowing how a bad code looks like. With this in mind, this is not what to do in an ASP.NET MVC view:


~/Views/Home/Index.cshtml
@model SoQna.ViewModels.QnaViewModel

@using (Html.BeginForm("SubmitAnswers", "Home"))
{
    int i = 0;
    foreach (SoQna.ViewModels.AnswerToQuestion answer in Model.Answers)
    {
        @: Question #@(answer.ToQuestionId) <br />

        @Html.Hidden("Answers[" + i + "].ToQuestionId", answer.ToQuestionId)
        @Html.DisplayFor("Answers[" + i + "].QuestionText", answer.QuestionText)

        <p />

        @Html.TextArea("Answers[" + i + "].AnswerText", answer.AnswerText)

        <hr />
        
        ++i;
    }

    <input type="submit" value="Done" />
}

Sure that code is very model-centric and capable of being directly usable by our controller code...


// POST /Home/SubmitAnswers

[HttpPost]
public ViewResult SubmitAnswers(SoQna.ViewModels.QnaViewModel a)
{
    foreach (SoQna.ViewModels.AnswerToQuestion answer in a.Answers)
    {
        answer.QuestionText = _qnaRepo.Single(x => x.QuestionId == answer.ToQuestionId).QuestionText;
    }
    return View(a);
}


...but the problem with the ~/Views/Home/Index.cshtml view above is we cannot use strongly-typed model on html helpers. As much as possible, with strongly-typed framework such as ASP.NET MVC, we should not use magic strings in our code. We should let strong typing take over the reins in our ASP.NET MVC app. With this in mind, we shall do this instead on ~/Views/Home/Index.cshtml:

@model SoQna.ViewModels.QnaViewModel

@using (Html.BeginForm("SubmitAnswers", "Home" ))
{    
    @Html.EditorFor(x => x.Answers) 
    <input type="submit" value="Done" />
}

Now you might ask, where's the loop? How does it know how to display the corresponding HTML for our object's properties?

On first question, Html.EditorFor does the loop for us if the property is an IEnumerable one. On second question, that's where we will use the EditorTemplates. When you want to use a pre-defined view(editor template) for a given model or view-model, you place that view in this folder ~/Views/Shared/EditorTemplates, but if you intend your pre-defined view for a given model/view-model be a controller-specific one, placed them in their specific controller folder, e.g. ~/Views/XXX/EditorTemplates where XXX is your controller name. ASP.NET MVC will first look for editor templates specific to your controller; if it cannot find one, it will look in ~/Views/Shared/EditorTemplates folder


To make our first editor template, please create an EditorTemplates folder on ~/Views/Home, given Home is your controller name. Then add an MVC 3 Partial Page (Razor) item to your ~/Views/Home/EditorTemplates folder, you do this by doing a right-click on EditorTemplates and selecting Add > New Item

Name your editor template Razor page after your model type or view-model type.

This is how our ~/Views/Home/EditorTemplates/AnswerToQuestion.cshtml shall look like:

@model SoQna.ViewModels.AnswerToQuestion

Question #@(Model.ToQuestionId) <br />
@Html.HiddenFor(x => x.ToQuestionId)
@Html.DisplayFor(x => x.QuestionText)

<p />

@Html.TextAreaFor(x => x.AnswerText)

<hr />

Here's a sample output:



Download: http://code.google.com/p/aspnet-mvc-demo-editor-templates/downloads/list

SVN: http://code.google.com/p/aspnet-mvc-demo-editor-templates/source/checkout

Friday, April 27, 2012

Multiple dispatch in C#

This code...

using System;


public class MainClass {

    public static void Main() {
        Asset[] xx = { new Asset(), new House(), new Asset(), new House() };

        foreach(Asset x in xx) {
            Foo(x);
        }
    }

        
    public static void Foo(Asset a) {
        Console.WriteLine("Asset");
    }

    public static void Foo(House h) {
        Console.WriteLine("House");
    }

}


public class Asset {
}

public class House : Asset {
}



...outputs:

Asset
Asset
Asset
Asset


If you want an output of Asset, House, Asset, House, i.e. you want to use the overloaded method that matches the object type(House) not by object's reference type(on this expression, Asset is the reference type: foreach(Asset x in xx), we are using Asset as a reference for some of the House object in array of Asset object), there are multiple approach to solve the problem, one is to design your class polymorphism by using virtual and override; another is to amend the Foo(Asset a) code.
Another way is to use dynamic of C# 4, this is covered on later part of this post

Let's try with this one:
public static void Foo(Asset a) {
    if (a.GetType() == typeof(Asset))
        Console.WriteLine("Asset");
    else if (a.GetType() == typeof(House))
        Foo((House) a);
}

That's too much for asking on the developer of Foo(Asset a). What if there's another class that derives Asset? Say Car, that would entail adding another else if (a.GetType() == typeof(Car)), and what's more difficult is you cannot know in advanced what new classes will derive from Asset. And that approach is an antithesis of http://www.antiifcampaign.com/

You can call the runtime-matched method by using reflection for those purposes:

using System;


public class MainClass {

    public static void Main() {
        Asset[] xx = { new Asset(), new House(), new Asset(), new House(), new Car() };

        foreach(Asset x in xx) {
            Foo(x);
        }
    }

        
    public static void Foo(Asset a) {
 
        if (a.GetType() == typeof(Asset))
            Console.WriteLine("Asset");
        else {
            Type t = typeof(MainClass);
            t.InvokeMember("Foo", System.Reflection.BindingFlags.InvokeMethod, null, 
                t, new object[] { a } ); 
        }

    }

    public static void Foo(House h) {
        Console.WriteLine("House");
    }

    public static void Foo(Car c) {
        Console.WriteLine("Car");
    }

}


public class Asset {
}

public class House : Asset {
}

public class Car : Asset {
}


Outputs:
Asset
House
Asset
House
Car


If you are using C# 4, you can use dynamic to avoid resorting to reflection, and code-wise it has less friction(if you don't treat casting to dynamic as friction) on your code, i.e. you don't need to modify the Foo(Asset a), dynamic feature is worth considering if Foo helpers comes in binary form, i.e. no source code.

using System;


public class MainClass {

    public static void Main() {
        Asset[] xx = { new Asset(), new House(), new Asset(), new House(), new Car() };

        foreach(Asset x in xx) {
            Foo((dynamic)x);
        }
    }

        
    public static void Foo(Asset a) {
        Console.WriteLine("Asset");
    }

    public static void Foo(House h) {
        Console.WriteLine("House");
    }

    public static void Foo(Car c) {
        Console.WriteLine("Car");
    }

}


public class Asset {
}

public class House : Asset {
}

public class Car : Asset {
}

Outputs:
Asset
House
Asset
House
Car


Another good thing with multiple dispatch via dynamic as compared to reflection, dynamic multiple dispatch is similar with polymorphism that happens on recommended class polymorphism(i.e. one that uses virtual & override), i.e. if there's no available overloaded static method for a given derived class, dynamic will automatically find a method that best matches the given derived class, and what best matches the derived class than its base class? Nice, isn't it? :-)

So in our code example, if we remove the public static void Foo(Car c) from the code above, the Car type will be resolved by dynamic to invoke Foo Asset overload instead, the output is:

Asset
House
Asset
House
Asset


Whereas if you use static method invocation using reflection, you don't have that kind of luxury, the output for reflection approach when public static void Foo(Car c) is not available:

Asset
House
Asset
House


Notice the absence of 5th output? Your code will just fail silently if you just have the kind of reflection code above.

If you want to use the Foo Asset overload for Car type on absence of Foo Car overload, you have to find a way how reflection can invoke the base type overload given the absence of actual type overload, and perhaps a bit of google-fu or stackoverflow-fu could help you find a solution for this problem. Please advise me if you find out how ツ

Monday, April 23, 2012

OUTER APPLY Walkthrough

Given a task to display the nearest immediate elder brother's birthdate of a given Person, we might come up with subquery.

create table Member
(
 Firstname varchar(20) not null, 
 Lastname varchar(20) not null,
 BirthDate date not null unique
);

insert into Member(Firstname,Lastname,Birthdate) values
('John','Lennon','Oct 9, 1940'),
('Paul','McCartney','June 8, 1942'),
('George','Harrison','February 25, 1943'),
('Ringo','Starr','July 7, 1940');



Assuming that no persons share the same birthdate, this is how we might code it in subquery:


select m.*,
  
 ElderBirthDate = 
  (select top 1 x.BirthDate 
  from Member x 
  where x.BirthDate < m.BirthDate 
  order by x.BirthDate desc)
  
from Member m
order by m.BirthDate;


Now, some nasty users requested for more information, she wanted to see that elder person's Firstname too; as a good developer you are, of course you will comply. Here's your new query:

select m.*,

 ElderBirthDate = 
  (select top 1 x.BirthDate 
  from Member x 
  where x.BirthDate < m.BirthDate 
  order by x.BirthDate desc),
 ElderFirstname = 
  (select top 1 x.Firstname 
  from Member x 
  where x.BirthDate < m.BirthDate 
  order by x.BirthDate desc)
  
from Member m
order by m.BirthDate

Output:
Firstname            Lastname             BirthDate  ElderBirthDate ElderFirstname
-------------------- -------------------- ---------- -------------- --------------------
Ringo                Starr                1940-07-07 NULL           NULL
John                 Lennon               1940-10-09 1940-07-07     Ringo
Paul                 McCartney            1942-06-08 1940-10-09     John
George               Harrison             1943-02-25 1942-06-08     Paul

(4 row(s) affected)


Then a day after, she requested to add the Lastname, she deemed that it is nice to have that information on the report too. Things are getting hairy isn't it? We are violating DRY principle, if we are using subquery approach.


Enter OUTER APPLY, this neat technology is ought to be present in all RDBMS, unfortunately(if you expect that it is available on all RDBMS at the time of this writing) this is available on SQL Server only:

select m.*, elder.*
from Member m
outer apply
(
 select top 1 ElderBirthDate = x.BirthDate
 from Member x 
 where x.BirthDate < m.BirthDate 
 order by x.BirthDate desc
) as elder
order by m.BirthDate

Compared to subquery, at first glance it doesn't seem to add much in terms of value; but where it shines is it can pick up all the columns on the matched condition. Now back to the requested new column on report by our dear user, we can neatly add those column(s) if we are using OUTER APPLY instead:

select m.*, elder.*
from Member m
outer apply
(
 select top 1 ElderBirthDate = x.BirthDate, ElderFirstname = x.Firstname
 from Member x 
 where x.BirthDate < m.BirthDate 
 order by x.BirthDate desc
) as elder
order by m.BirthDate

Firstname            Lastname             BirthDate  ElderBirthDate ElderFirstname
-------------------- -------------------- ---------- -------------- --------------------
Ringo                Starr                1940-07-07 NULL           NULL
John                 Lennon               1940-10-09 1940-07-07     Ringo
Paul                 McCartney            1942-06-08 1940-10-09     John
George               Harrison             1943-02-25 1942-06-08     Paul

(4 row(s) affected)


Not only there is less friction on modifying our query based on user's requests when we uses OUTER APPLY, our OUTER APPLY query scales nicely too:



Now there's a new request in town to display the person's two immediate elder brothers; if we are using subquery, we might cringe at the thought of rewriting our query just to facilitate such whimsical requirement. But hey, we are using OUTER APPLY, you can laugh in triumph rather than quivering in pain, just modify the TOP 1 to TOP 2 to support that requirement. Convenient isn't it?

select m.*, elder.*
from Member m
outer apply
(
 select top 2 ElderBirthDate = x.BirthDate, ElderFirstname = x.Firstname
 from Member x 
 where x.BirthDate < m.BirthDate 
 order by x.BirthDate desc
) as elder
order by m.BirthDate, elder.ElderBirthDate desc


Output:
Firstname            Lastname             BirthDate  ElderBirthDate ElderFirstname
-------------------- -------------------- ---------- -------------- --------------------
Ringo                Starr                1940-07-07 NULL           NULL
John                 Lennon               1940-10-09 1940-07-07     Ringo
Paul                 McCartney            1942-06-08 1940-10-09     John
Paul                 McCartney            1942-06-08 1940-07-07     Ringo
George               Harrison             1943-02-25 1942-06-08     Paul
George               Harrison             1943-02-25 1940-10-09     John

(6 row(s) affected)


Live test: http://www.sqlfiddle.com/#!3/19a63/1

Saturday, April 21, 2012

If Your Only Tool Is A Lambda, All Your Problems Will Look Like Can Be Tackled By Lambda Only

I love lambda, you love lambda, we all love lambda. When we neo-.NET kids encounters a problem that involves anything enumerable, we launch right away our lambda-fu into stratosphere, not even taking into account that there might be a simpler way to tackle the problem


For example, given a problem to sum all BigIntegers, we tend to solve it in lambda-ish way sort of way. But since a BigInteger lacks a Sum lambda/extension method, we are inclined to write it with what is available to us, i.e. we use Aggregate lambda:


using System;
using System.Linq;

using System.Numerics;

using System.Collections.Generic;


class Great 
{
 public static void Main() 
 {
  var bigInts = new List<System.Numerics.BigInteger>() {1, 2, 3, 4};

  var result = bigInts.Aggregate((currentSum, item)=> currentSum + item);
   
  Console.WriteLine(result);
 
 }
}



However, we forget that there's already a simpler alternative available to us, which is BigInteger's helper Add method. Given lambda's popularity, we tend to forget that lambdas can be fed with helper methods. If there's already a predefined helper method for a given problem, by all means use them to simplify things up. The code above could be rewritten by using predefined helper:

var bigInts = new List<System.Numerics.BigInteger>() {1, 2, 3, 4};

var result = bigInts.Aggregate(BigInteger.Add);   

Console.WriteLine(result);

Output:
10


So there we are, we can use predefined helper method, simple and has lesser noise. Lest we forgot, lambdas are just inlined delegates; so if there's already a predefined helper method that matches the lambda's delegate signature, feel free to use that helper method

Thursday, April 19, 2012

ServiceStack Walkthrough. Screenshots guide

Create an ASP.NET MVC Project:




Add ServiceStack components (ServiceStack.dll, ServiceStack.Interfaces.dll):



Get the DLLs at: https://github.com/ServiceStack/ServiceStack/downloads


Add this line to Web.config's httpHandlers section:

<add path="yourServicestack*"
 type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" />



Put this inside configuration section:


<location path="servicestack">
  <system.web>
    <httpHandlers>
      <add path="*" 
        type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" 
        verb="*" />
    </httpHandlers>
  </system.web>
</location>



Add these lines on RegisterRoutes:
routes.IgnoreRoute ("yourServicestack");
routes.IgnoreRoute ("yourServicestack/{*pathInfo}");



Add these Request,Response,Service classes in your Models directory:


class Hello  
{
 public string Name { get; set; }
   
}

class HelloResponse
{
 public string Result { get; set; }   
}

class HelloService : ServiceStack.ServiceHost.IService<Hello>
{
 public object Execute(Hello request) 
 {
  return  new HelloResponse { Result = "Good morning " + request.Name + "!" };
 }
} 









And add these other Request,Response,Service classes in Models directory too:


class Subtraction 
{ 
 public decimal Minuend { get; set; }  
 public decimal Subtrahend { get; set; }  
}


class SubtractionResponse 
{
 public decimal Difference { get; set; }
}

class SubtractionService : ServiceStack.ServiceHost.IService<Subtraction>
{
 public object Execute(Subtraction request) 
 {      
  return  new SubtractionResponse { Difference = request.Minuend - request.Subtrahend };
 }
}


Add these code in Global.asax.cs:


protected void Application_Start ()
{
 RegisterRoutes (RouteTable.Routes);
  
 new NextBillionAppHost().Init();
}



public class NextBillionAppHost : ServiceStack.WebHost.Endpoints.AppHostBase
{
 //Tell Service Stack the name of your application and where to find your web services
 public NextBillionAppHost() 
    : base("Billionaire Web Services", 
          typeof(DemoServiceStack.Models.SubtractionService).Assembly) { }

 public override void Configure(Funq.Container container)
 {       
  //register user-defined REST-ful urls
  Routes
   .Add<DemoServiceStack.Models.Hello>("/como-esta")
   .Add<DemoServiceStack.Models.Hello>("/como-esta/{Name}");
  
  Routes
   .Add<DemoServiceStack.Models.Subtraction>("/solve-subtraction")     
   .Add<DemoServiceStack.Models.Subtraction>("/solve-subtraction/{Minuend}/{Subtrahend}");
 }
}



Then run (shortcut key: command+option+enter), then type in address bar:


http://127.0.0.1:8080/yourServicestack

,then you shall see this:



Then under Operations, click the JSON tag of Subtraction operation, you shall see this:



Then type this url in the address bar:

http://127.0.0.1:8080/yourServicestack/solve-subtraction/2011/1955

You shall see this:



Then try to click the JSON, XML, etc, see the output.


You can use ServiceStack instead of WCF. REST-ful services is easier with ServiceStack. ServiceStack has a good programming model, i.e. the Request, Response and their Service has good cohesion