5/26/2008

LocalizationFilterAttribute

The MVC Framework is highly extensible, which makes it really fun to tinker around with ;) . I just got done integrating jQuery based AJAX and JSON request/response patterns, using different variations of the work laid out by Aaron Lerch in Unifying Web "Sites" and Web Services with the ASP.NET MVC Framework and Nikhil Kothari in Ajax with the ASP.NET MVC Framework . I was surprised to find so many different extension points built into the framework, it really gives you the power to do just about anything.

I though it might be great to leverage this extensibility and add localization into my new WebSite/WebService monster.

When it comes to localization on the human web, we have a few choices.

  1. The Accept-Language HTTP Header Field is supported by most browsers and a lot of sites.
  2. Some sites, like MSDN Library, allow users to put the desired language-culture specifier in the request URL. (en-US, es-ES, fr-FR, etc).
When I was working for Microsoft in Japan, I loved the fact that KB articles and the MSDN library supported language-culture specifier in the request URL. This allowed me to do my research in English, change the URL from 'en-US/whatever' to 'ja-JP/whatever', and send the resulting URL to my native Japanese customers. So option #2 is what I chose.

I'm using the SimplyRestfulRouteHandler to establish my routing, so this is what my route registration looked like:

SimplyRestfulRouteHandler.BuildRoutes(RouteTable.Routes, "{lang}");

You could also do it the old-fashioned way:

RouteTable.Routes.Add(new Route(
"{lang}/{controller}",
new {Action = "Index", Controller = controllerName},
new RouteValueDictionary(new { httpMethod = "GET" }),
new MvcRouteHandler()));

Now the Controller.RouteData.Values["lang"] key will store the specified language-culture for a GET request like 'http://msdn.microsoft.com/en-us/library', where library is the controller.

Next, I want to snag that value and use it to set my thread's CurrentCulture/CurrentUICulture properties. I also want to make sure that I revert the thread's settings when my action is done processing because these properties won't be reverted if our thread is executing in a ThreadPool.

Fortunately, the ActionFilterAttribute class exposes an OnActionExecuting() method which is triggered before an action executes, and a OnActionExecuted() method which is triggered right after. So, I created the following LocalizationFilterAttribute class to do the dirty work for me.

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public class LocalizationFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Controller c = filterContext.Controller as Controller;
if(c == null)
return;

string lang = c.RouteData.Values["lang"] as string;
if(lang == null)
return;

try
{
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(lang);
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(lang);
}
catch
{
throw new NotFoundException("The specified language " + lang +
" was not found.");
}
}

public override void OnActionExecuted(ActionExecutedContext filterContext)
{
Thread.CurrentThread.CurrentCulture = CultureInfo.InstalledUICulture;
Thread.CurrentThread.CurrentUICulture = CultureInfo.InstalledUICulture;
}
}

It's a good idea to reset the culture information in the Application_Error (Global.asax.cs) method as well, in case an unexpected exception causes the action to terminate.

protected void Application_Error(object sender, EventArgs e)
{
Thread.CurrentThread.CurrentCulture = CultureInfo.InstalledUICulture;
Thread.CurrentThread.CurrentUICulture = CultureInfo.InstalledUICulture;
}

That's all there is to it. You can throw this filter attribute on any controller class you want, and you're ready to localize.

5/07/2008

Vibrant Ink

Like everyone else on the block, I've been using a black theme similar to Vibrant Ink in most of my text editors.

You can grab those themes here.

Have fun!

4/27/2008

SimplyRestfulRouteHandler Sample

MvcContrib is packed with quite a few gems. One of these is the SimplyRestfulRouteHandler, a route utility created by Adam Tybor.

Using the SimplyRestfulRouteHandler, the following 10 Routes are assigned to the 8 Actions below.
(Blatantly lifted from Adam's site)

ActionUrlHttp MethodForm Method
Show[controller]/[id]GET
Create[controller]POST
Update[controller]/[id]PUT
Update[controller]/[id]POSTPUT
Destroy[controller]/[id]DELETE
Destroy[controller]/[id]POSTDELETE
Index[controller]GET
New[controller]/newGET
Edit[controller]/[id]/editGET
Delete[controller]/[id]/deleteGET

The route handler is surprisingly easy to use, but it can be tricky to set up if you are not familiar with the new method signatures of the latest MVC source code refresh.

I created a sample app based on the MVC HomeController that highlights the 8 actions defined by the SimplyRestfulRouteHandler. To follow along, you will need the 4/16 MVC source code refresh (build 0416) and the 4/19 release of the MvcContrib library (0.0.1.101).

First you should create a new 'ASP.NET MVC Web Application' project from the 'My Templates' portion of the 'New Project' dialog. If you use the template of the same name under the 'Visual Studio installed templates' portion, you will be using the latest official release of MVC and not the source code refresh.

In the global.asax.cs file, replace the RegisterRoutes method with the following.

public static void RegisterRoutes(RouteCollection routes)
{
SimplyRestfulRouteHandler.BuildRoutes(routes);
}

This will allow the route handler to build all 10 routes for you, based on templates listed in the table above.
Next we open the HomeController.cs file and add the corresponding actions.


public ActionResult Show(string id)
{
ViewData["Title"] = "Show";
ViewData["Message"] = "This will <em>Show</em> resource " + id;

return RenderView("Index");
}

public ActionResult Create()
{
ViewData["Title"] = "Create";
ViewData["Message"] = "This will <em>Create</em> a new resource";

return RenderView("Index");
}

public ActionResult Update(string id)
{
ViewData["Title"] = "Update";
ViewData["Message"] = "This will <em>Update</em> resource " + id;

return RenderView("Index");
}

public ActionResult Destroy(string id)
{
ViewData["Title"] = "Destroy";
ViewData["Message"] = "This will <em>Destroy</em> resource " + id;

return RenderView("Index");
}

public ActionResult Index()
{
ViewData["Title"] = "Index";
ViewData["Message"] = "This is the <em>Index</em>";

return RenderView("Index");
}

public ActionResult New()
{
ViewData["Title"] = "New";
ViewData["Message"] = "This will create a <em>New</em> resource";

return RenderView("Index");
}

public ActionResult Edit(string id)
{
ViewData["Title"] = "Edit";
ViewData["Message"] = "This will <em>Edit</em> resource " + id;

return RenderView("Index");
}

public ActionResult Delete(string id)
{
ViewData["Title"] = "Delete";
ViewData["Message"] = "This will <em>Delete</em> resource " + id;

return RenderView("Index");
}

For this sample app, all we really want to do is simply display a brief message letting us know which action the user wanted to take. The generated 'Index.aspx' view is fine for this, so we can set the viewName parameter of the RenderView() method to "Index" for all actions, as shown above.

Now we have just about everything we need. Let's move on to the 'Site.Master' file and enable the user to generate all 8 actions via click events.

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
AutoEventWireup="true" CodeBehind="Create.aspx.cs"
Inherits="RestfulSample.Views.Home.Index" %>

<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
<%= ViewData["Message"] %>
<p>
To learn more about ASP.NET MVC visit
<a href="http://asp.net/mvc" title="ASP.NET MVC Website">
http://asp.net/mvc</a>.
</p>
</asp:Content>

Now we have just about everything we need. Let's move on to the 'Site.Master' file and enable to user to generate all 8 actions via click events.

<ul id="menu">
<li> <%= Html.ActionLink("Show GET", "Show", "Home", new { @id="1" }) %> </li>
<li> <%= Html.ActionLink("Index GET", "Index", "Home")%> </li>
<li> <%= Html.ActionLink("New GET", "New", "Home")%> </li>
<li> <%= Html.ActionLink("Edit GET", "Edit", "Home", new { @id = "1" })%> </li>
<li> <%= Html.ActionLink("Delete GET", "Delete", "Home", new { @id = "1" })%> </li>
<li>
<form action="<%= Url.Action("Create", "Home") %>" method="post" >
<a onclick="parentNode.submit();">Create POST</a>
</form>
</li>
<li>
<form action="<%= Url.Action( "Update", "Home", new { @id = "1" }) %>" method="post" >
<input type="hidden" name="_method" value="put" />
<a onclick="parentNode.submit();">Update POST</a>
</form>
</li>
<li>
<form action="<%= Url.Action( "Destroy", "Home", new { @id = "1" }) %>" method="post" >
<input type="hidden" name="_method" value="delete" />
<a onclick="parentNode.submit();">Destroy POST</a>
</form>
</li>
</ul>

If you were watching closely, you should have noticed that the POST events have a hidden input element named "_method" who's value is an HTTP method (PUT or DELETE). Well, most browsers don't support these two methods so we sometimes need a clever way of initiating these requests. Adam was kind enough to wire up our Destroy and Update Actions so that they fire when the route manager receives standard HTTP PUT and DELETE methods OR when it receives a browser-friendly HTTP POST request with a PUT or DELETE "_method" defined.

Next we need to make the form elements of our menu look pretty, so we add the following to our 'Site.css' file.

ul#menu li form
{
display: inline;
list-style: none;
}

And that's all there is to it. You should be able to launch the application and click on all of the menu items to generate any of the 8 RESTful actions.

You can download the complete source for this sample project here.

4/17/2008

ActiveResource

While I was driving home from work today I was thinking about how easy it would be enhance the Dream/Subsonic stuff I've been working with and write a custom proxy-class generator for c#. I was thinking "You know... if I did it right, it would look a lot like the active-record pattern. Wonder what I should call it... 'ActiveREST'?"

Well, a quick search turned up the Rails 'Active Resource' pattern ;). I'm glad someone's already doing it, it proves that this may indeed be a useful pattern to have. I'll have to start digging into Active Resource more... wish I would have found this two weeks ago, when I started this little experiment.

4/16/2008

Dream CRUD ;)

Background
For the last two weeks or so, I have playing with the MindTouch Dream framework (.NET REST) and the new Subsonic dynamic query generator. Initially the idea was to create one or two quick and dirty APIs that allow me to perform basic CRUD operations on resources that I will be storing in a database. I did write these one or two APIs, and pretty soon I realized that this access pattern was fairly powerful. It does not take full advantage of all that REST has to offer, for example it only allows XML formatted payloads, but if it is used correctly I think there is a lot I could gain from this access pattern. So I decided to broaden the scope a bit and create some base functionality that would allow me to leverage this access pattern in a more generic fashion.

Result
Essentially, I've created a way to selectively expose some of my database resources via REST. The whole idea revolves around using Dream's performant and easy to use XDoc class as a DTO wrapper around XML resources. Then I use Subsonic to generate clean, dynamic queries that will execute against any of Subsonic's supported dataproviders; a list that includes MySql, MS Sql, and Oracle.

Here's an example CRUD method, which retrieves a row of data from a table by a specified key name/value pair.


protected static DreamMessage GetTableAsMessageByKey(
string rootNodeTag,
string tableName,
string keyColumn,
object keyValue)
{
DreamMessage message;
XDoc doc;

try
{
if (rootNodeTag == null) throw new ArgumentNullException("rootNodeTag");
if (tableName == null) throw new ArgumentNullException("tableName");
if (keyColumn == null) throw new ArgumentNullException("keyColumn");
if (keyValue == null) throw new ArgumentNullException("keyValue");

doc = new Select().From(tableName).Where(keyColumn).IsEqualTo(keyValue)
.ExecuteXDoc(keyColumn, rootNodeTag, null);

if ((doc == null) || (doc.Count() < 1))
throw new NotFoundException("{3ED0B0F0-2C92-49e1-B710-1CC30CC2F769}",
Resources.DATA_ID_NOT_FOUND,
new[] { rootNodeTag, keyColumn, keyValue });

message = DreamMessage.Ok(doc);
}
catch (Exception ex)
{
message = HandleException("{4FCDA723-C0E6-4316-8F0F-3A9D20484C08}",
string.Format("GetTableMessageById(rootNodeTag={0}, tableName={1}, " +
"keyColumn={2}, keyValue={3})", rootNodeTag ?? "", tableName ?? "",
keyColumn ?? "", keyValue ?? ""), ex);
}

return message;
}


The SubSonic Select() query statement I use ends with ExecuteXDoc() which is a .NET 3.5 extension that I added to perform an IDataReader -> XDoc mapping.

I've also added some of pluming that's specific to my needs. The NotFoundException() will cause a DreamMessage with a 404 (not found) HTTP status code to be created and return to the client; the title and message of the response will be localized to match the client's language specification. The HandleException() method takes care of DreamMessage creation, and it writes a log entry using the log4net logger.

Here's an example GET method declaration that uses this generic mapping pattern.


[DreamFeature("GET:{lang}/modules/{id}", "Get modules.")]
[DreamFeatureParam("{lang}", "string", "The requestors preferred language")]
[DreamFeatureParam("{id}", "int", "The id of the module to get")]
public Yield GetModuleById(
DreamContext context,
DreamMessage request,
Result<DreamMessage> response)
{
string lang = context.GetParam<string>("lang");
int id = context.GetParam<int>("id");

try
{
SetCurrentCulture(lang);
response.Return(GetTableAsMessageByKey("Module", "core_module", "id", id));
}
catch (Exception ex)
{
response.Return(HandleException(
"{AB360F60-EDF0-4734-BA53-99A38C220664}",
string.Format("GetModuleById(lang={0}, moduleId={1}",
lang, id), ex));
}
finally
{
ResetCurrentCulture();
}

yield break;
}


And a response generated from a GET to '/en-US/modules/2'


<Module xml:id="2">
<create_date>2008-04-01T04:12:52Z</create_date>
<modified_date>2008-04-01T04:12:52Z</modified_date>
<modified_user>1</modified_user>
<version>1</version>
<provides_namespace>tempuri</provides_namespace>
<base_uri>tempuri/base</base_uri>
<active>true</active>
</Module>


Benefits
This access pattern provides several benefits.
  • Performance - Because I am not using any intermediate DTO classes or business objects, I don't have to go through the entire "deserialize request -> retrieve data -> map data to object -> serialize object as response" lifecycle. this solution is very performant.
  • Database Agnostic - SubSonic allows me to talk to just about any database I would be interested in supporting, and the query format will not change based on the database I am using.
  • Customizable - I'm in control of any special processing I want to do. I'm already returning application-specific localized messages and doing custom logging on the server-side. In the future I want to be able to perform authorization based restrictions on select operations. This solution allows me to do all of that and more.
  • Easy - with a full set of CRUD operations already in place, I'm able to crank out access to my database-centric resources in minutes.
  • Consistent - all of the resources I expose using this pattern will be formatted in the same, predictable format, which makes it easier for clients to consume. For example, I'm using the 'xml:id' attribute to identify the object's key field. Because I'm also enforcing consistency in my database schema (naming conventions, common set of required fields, etc) a certain level of consistency trickles back to the client by default.
Limitations
Obviously there are several limitations. This implementation forces you to expose your database schema as your payload, which is not desirable in many situations. Additionally, the ability to perform complex validation or business logic spanning more than one resource type is difficult.

But even with these limitations in mind, I know this pattern is going to help me ease the pain of implementing the 20% or more CRUD-only operations I run into every day when creating enterprise-level applications.

4/07/2008

Interlocked Class

Sometimes you'll be digging through some code and run across a system class or method that you've never seen before. Today I found this gem.


Interlocked.Increment(ref safeInstanceCount);

The Interlocked class provides a simple and elegant way to perform thread-safe atomic increment, decrement and add operations.

Free Learning from Microsoft

Free E-Learning
Clinic 6262: Introducing Windows Workflow Foundation using .Net Framework 3.5 & Visual Studio 2008
Clinic 6263: Introducing Windows Presentation Foundation using .Net Framework 3.5 & Visual Studio 2008
Clinic 6264: Introducing Windows Communication Foundation using .Net Framework 3.5 & Visual Studio 2008
Free E-Book (MS Press)
Introducing Microsoft LINQ by Paolo Pialorsi and Marco Russo
Introducing Microsoft ASP.NET AJAX by Dino Esposito
Introducing Microsoft Silverlight 1.0 by Laurence Moroney
Enjoy!