# Wednesday, August 19, 2009

I’m really liking Ruby on Rails for numerous reasons, and chief among these reasons is the ability to make a change to Ruby code and then refresh the browser to see the changes.  In other words I really like to avoid paying taxes, and in this case the compilation tax we all pay when using a static language.

For a couple of years now, since I started using MonoRail back in 2007 I’ve always felt that productivity could be improved by writing not only views in a dynamic language, but the controllers too (maybe the entire app). There’s just something refreshing about making a change in server side code and immediately see the changes without waiting 30 seconds for a complete recompile of the entire application.

Yesterday I was heavily doing some TDD on a very low level componenent in our application and wasted about 10 minutes waiting for Visual Studio to recompile the project I was working on… and then every other project that depends on that one. It takes a lot of focus to keep the TDD rhythm going when you’re forced to wait 1 minute between runs.  I just have one word for this, painful.

I can only imagine the benefits of doing TDD with a dynamic language since you have a whole lot more compile and test cycles with TDD than traditional programming techniques. The emergence of TDD over the past few years along with general acceptance of the practice will only further push teams towards dynamic languages. Sure you lose static type safety, but that’s why we have lots of good unit tests; and at the controller level that’s not a bad thing because you’re often dealing with key value pairs (think web form post or json DTOs) and a dynamic language is just a much more natural fit.

I’m not completely sold that unit testing at the controller level always makes sense, it often involves too many collaborators and whole lot of mocking. With automocking this isn’t so bad, but sometimes you have complex Ajax interactions in the middle and testing at a higher level via a web test sometimes makes more sense.

I’m hoping Microsoft seriously starts supporting dynamic languages (the DLR) and makes it a first class citizen rather than pushing it to the side in favor of more C# language sugar. I was very disappointed to see that Visual Studio 2010 has no support what so ever for Python or Ruby (unless I completely missed it somehow). Actually, I was shocked! The future belongs to dynamic languages and Microsoft is almost completely ignoring them. If they would support them officially along with ASP.NET MVC, the .NET world would be a whole lot better off.  Without dynamic languages the ASP.NET MVC 2 gets a B in my grade book (version 1 gets a C). Maybe its time to switch platforms?

.NET | IronPython | MonoRail | RoR
Wednesday, August 19, 2009 3:47:59 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Tuesday, June 10, 2008

Sensitive information on your website should be encrypted between the client and the server, which generally means we need to use SSL (https).  How do we require SSL on specific MonoRail controllers or URLs?

With ASP.NET you could go into IIS and just check the "Require SSL" checkbox for a particular ASPX page.  With MonoRail, or even ASP.NET MVC, there's no corresponding resource on disk for IIS.  So how do we enable SSL at the controller level?

First off you need to add a certificate to your site in IIS, make sure you don't check "Require SSL" at the site level otherwise all requests will need to be over https. Remember we want finer grained SSL settings.

The solution I came up with was to create a MonoRail filter that gets runs before every action on a controller.  This declarative solution using attributes is much better than a base class since it can easily be added or removed from a controller.

   1: public class SecureChannelFilter : IFilter
   2: {
   3:     public const string AppKey = "SecureChannelFilterDisabled";
   4:  
   5:     public bool Perform(
   6:         ExecuteWhen exec,
   7:         IEngineContext context,
   8:         IController controller,
   9:         IControllerContext controllerContext)
  10:     {
  11:         if (context.Request.IsLocal)
  12:             return true;
  13:  
  14:         if (context.Request.Uri.Scheme == "https")
  15:             return true;
  16:  
  17:         bool disabled;
  18:         bool.TryParse(ConfigurationManager.AppSettings[AppKey], out disabled);
  19:         if (disabled)
  20:             return true;
  21:  
  22:         context.Response.StatusCode = 403;  // access forbidden
  23:         return false; // don't continue with request
  24:     }
  25: }

As you can see from the code, the filter allows local requests through without SSL but requires SSL for all other requests unless the filter has been configurationally disabled.  This allows us to run without SSL on our local development boxes.

If a request requires SSL and is not coming in over SSL, this filter then returns a 403 (Forbidden) status code which will then end up showing the IIS 403 error page.  If you wanted to get real fancy you could change your 403 error page to just redirect you back to the requested page, but using https instead of http.

To require SSL for a particular controller, like lets say a credit card controller, we would add the Filter attribute specifying the SecureChannelFilter:

   1: [Filter(ExecuteWhen.BeforeAction, typeof(SecureChannelFilter))]
   2: public class AccountDetailController
   3: {

With that in place we can feel confident that our controller will not be viewable without SSL.

Tuesday, June 10, 2008 7:31:41 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [2]  | 
# Thursday, January 17, 2008

Setting up Monorail to work on IIS7 isn't necessarily straight forward.  First you need to configure IIS7 to handle the particular file extension you are using for Monorail.  This is just like you would do in IIS6, but with some slightly different menus and terminology.

I'm using .rails for this particular application.  For the website or virtual directory you are configuring in IIS7, open the Handler Mappings in IIS Manager.

HandlerMappings

From there create a new Script Map, by clicking "Add Script Map..."  This opens the Script Map dialog.  You should enter *.rails as the request path and the aspnet_isapi.dll path as the executable.

EditScriptMap

Once that is done, click "Request Restrictions" and then uncheck "Invoke Handler only if request is mapped to".

RequestRestrictions

Once that is done you may run into a problem with your monorail section in the web.config.  I had this error:

An error occurred creating the configuration section handler for monoRail: Object reference not set to an instance of an object.

 

Odd, my web.config works in IIS6 and in webdev.webserver.exe.  As it turned out I had to fill out the assembly element in my MonoRail section even though I'm using Windsor integration.  I've bolded the part I had to add below:

 

<monorail useWindsorIntegration="true">
  <controllers>
    <assembly>Sneal.Store.Commerce</assembly>
  </controllers>
  <viewEngines viewPathRoot="Views">
    <add type="Castle.MonoRail.Framework.Views.NVelocity.NVelocityViewEngine, Castle.MonoRail.Framework.Views.NVelocity" />
  </viewEngines>
</monorail>
Thursday, January 17, 2008 3:44:58 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [1]  | 
# Friday, January 04, 2008

For 15 minutes today I couldn't figure out why my Windsor configuration was blowing up with a mysterious and unrevealing error: "deserialize element cannot process element component."  This happened after I moved some configuration out of my main windor config to a new embedded resource config file. I thought is this a bug in Windsor?  After briefly looking through the Windsor test source it was pretty obvious that this is supported and tested.

It turns out that I forgot to include the "components" tag in my config file.  Argh!  The answer was right in front of me all this time, I just didn't see it - even after comparing my broken config to a working config.  I'm glad I'm not the only one to have this problem...

Friday, January 04, 2008 7:01:38 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [2]  | 
# Friday, December 14, 2007

Data binding DateTime fields in MonoRail is pretty powerful and flexible, but not really straight forward.  Most of the time you can just provide the domain object propery as an argument to the a form helper method, but with DateTime's split across multiple select boxes this doesn't work when you post back to your controller method.  To get DateTime's to work across several HTML select fields you need to explicitly provide the selected value like so:

$Form.Select("billing.accountExpiration", $billing.accountExpiration.Month, [1..12], "%{tabindex='11'}")
$Form.Select("billing.accountExpiration", $billing.accountExpiration.Year, [$DateTime.Now.Year..2011], "%{tabindex='12'}")

Friday, December 14, 2007 6:50:05 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, November 28, 2007

Today I discovered that in Monorail you must add an HTML name attribute to each element you want the SmartDispatchController to autowire for controller method parameters.

Without any name attributes on my emailAddress and password text boxes, the values were null that were passed into my controller method (BTW - isn't that a nice clean controller method?):

public void CreateAccount(string emailAddress, string password, string returnUrl)
{
    UserServiceResponse response = userService.CreateNewAccount(emailAddress, password);
    if (response.HasErrors)
    {
        Flash.Add("Summary", response.ErrorMessages);
        RedirectToAction("New", "ReturnUrl=" + returnUrl);
    }
    else
    {
        CancelView();
        Session[AuthenticationFilter.UserKey] = response.User;
        Redirect(returnUrl);
    }
}

 

Adding the "name" HTML attribute made the values auto populate as needed:

 

<input id="emailAddress" name="emailAddress" type="text" tabindex="1" />

Wednesday, November 28, 2007 11:53:29 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Monday, November 26, 2007

If you need to override the Prototype submit behavior in MonoRail's FormHelper.FormTag, you will need to use on_submit instead of onSubmit.  This isn't obvious since every other parameter seems to match up to the JavaScript libraries params.

With that out of the way I can hook my custom validation and display logic for a non-domain object ala Billy McCafferty's post.

Here's an example to override the onsubmit behavior:

$Form.FormTag("%{action='login', on_submit='false'}")

Monday, November 26, 2007 11:24:56 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Monday, November 12, 2007

There has been a lot of buzz over the past few days about ASP.NET MVC allowing developers to create RESTful URLs.  This turned out to be very good timing since I was implementing RESTful URLs without first realizing it in MonoRail last week.

I had to give a business partner two links to our new online service, one for each screen mode the partner's web device supported: splitscreen and fullscreen.  This got me thinking about the URLs I was providing, since I was essentially etching the URL in stone; I wanted to make sure they looked professional and provided maximum flexibility in the future.  It also got me wondering if I couldn't add additional information into the URL; information that in the past I would have stuck in a cookie or in a session. 

At first I put this extra data in the session, but then I started thinking about: session time out, load balancing, SQL Server DB, and scalability. Cookies might be better, but then I thought how the browser on these devices immediately asks you if you want to store a cookie - bad first impression.  It seemed the answer was to use the querystring and pass state around from one page to the next on the querystring, but I hated the idea of passing around a few values on every single page request.  This seemed fragile and made every page URL ugly and long.

I already knew that you generally want to use directories, or resources, over querystring parameters for web search engine optimization, but then I realized that using resources instead of querystring parameters is also more organized and user friendly.  Here's an example of two URLs, one using a querystring, and the other using a REST style resource URL.

http://sneal.net/fullscreen/categories/category1/page1

http://sneal.net/categories.rails?screenMode=fullscreen&category=1&page=1

I think its pretty obvious that the first (REST style) URL is much better for several reasons:

  • Easier to read, it's essentially just a directory path.
  • Easy to remember, it avoids strange symbols and is shorter.
  • Provides a nice structure to the data: categories -> 1st category -> 1st page.
  • It's discoverable.  Its pretty obvious what you can type in to go to page2 etc.

Another benefit is that links into your web application aren't tied to a particular technology or platform.  I've already experienced this at GalleryPlayer when we wanted to change some static HTML content into dynamic ASP.NET pages - external URLs weren't just looking for a resource, but they were explicitly looking for a static HTML page.  If we had implemented REST style URLs from the very beginning using URL rewriting, any external links could have been using a technology agnostic URL instead of a specific one tied to static HTML.

For example, I can point people to http://sneal.net/blog/somepost, rather than http://sneal.net/blog/blog.aspx?post=somepost.  If later on I decided to switch from dasBlog to a ROR based blog engine running on Linux, I could do that without anyone being the wiser.  The blog.aspx link would be much more difficult to change the underlying technology to ROR since the link includes the resource 'blog' and the view implementation type, 'aspx'.

Lets not forget what URL stands for: Uniform Resource Locator. In the end the consumer of your data shouldn't really care how you produce the results, whether you're using ASP.NET, MonoRail, ROR, PHP, or JSP.  The only thing the consumer should care about is the data your service, or web page, is providing - and where to find it at.  With an MVC framework like MonoRail, ROR, or ASP.NET MVC, URL routing couldn't be easier.

As K Scott Allen said, "The [ASP.NET] MVC framework is, I believe, about putting control in the hands of a web developer. Control over the routing of HTTP requests to components. Control over selecting the view. Control over state management, and control over the outgoing HTML."  I couldn't agree more.  URL routing/rewriting gives you a flexible abstraction layer between your URLs and your resource implementations.

In my next post I hope to show how I avoided session state and cookies by using REST style URLs with MonoRail.

Monday, November 12, 2007 7:25:08 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [1]  |