Christopher Bennage

Sponsors

The Lounge

Wicked Cool Jobs

Syndication

thinking out loud: asp.net mvc & nhaml

I’ve been playing around with the view engine nhaml and asp.net mvc. At the same time, I’m playing around with some architectural ideas in hope to benefit future projects.

I’m not doing any fancy yet, but I thought that it might be interesting to show you a couple of things to see what you think. Bear in mind, this is my sandbox code. I also suspect that I’m reinventing some wheels.

The context here is a page that allows a user to register for an account on the site.

First, the view looks like this:

%h2 Create Account

%form{method="post"}
  = Html.FormField<OpenAccount>(x=>x.AccountName)
  = Html.FormField<OpenAccount>(x=>x.EmailAddress)
  = Html.FormField<OpenAccount>(x=>x.Password)
  
  %input {type="submit" value="Save"}
  %button {onclick="javascript:history.back()" type="button"} Cancel

OpenAccount is my view model. (I hate how we’ve overloaded these  terms.)

I really like the succinctness of the nhaml, though I’m not ready to commit to it 100%. Spark is very attractive to me as well.

Html.FormField is an extension method I wrote. I’m toying with the idea of having it emit a <lablel /> paired with the <input />. Part of my motivation here is standardizing all of the label/inputs in my forms as well as a few experimental ideas about localization.

It’s rather naive at the moment, but here is the helper:

public static string FormField<T>(this HtmlHelper helper, Expression<Func<T, string>> property)
    where T : class, ICommand
{
    var model = helper.ViewData.Model as T;
    if (helper.ViewData.Model != null && model == null) throw new InvalidOperationException();

    var expression = (MemberExpression)property.Body;
    var name = expression.Member.Name;

    var value = (model == null)
                    ? null
                    : property.Compile().Invoke(model);

    return helper.TextBox(name, value);
}

Yeah, I hardcoded to a textbox for the moment. As I said, this is just a sandbox spike.

Finally, the associated controller action looks like this:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(OpenAccount form)
{
    var result = _backend.Execute(form);

    return result.Success
               ? (ActionResult) RedirectToAction("WhateverIsNext")
               : View(result);
}

I’m treating the incoming form as a command. The _backend is responsible for processing the command. The command is just information necessary to execute the command, not the logic to execute it. The result I’m getting back is actually an instance of the same command with information attached by the backend (e.g., did the command execute correctly, what were the validation errors). It’s not exactly SRP, however I’m influenced by the simplicity of RoR here.

One more interesting bit. I really don’t like having actions in my controller that do nothing other than render the view. For example:

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Create()
{
    return View();
}

So instead, I created a base controller that does this:

public class ControllerBase : Controller
{
    protected override void HandleUnknownAction(string actionName)
    {
        try
        {
            View(actionName).ExecuteResult(ControllerContext);
        }
        catch (InvalidOperationException e)
        {
            //show the error or something
        }
    }
}

Posted 10-02-2009 4:48 PM by Christopher Bennage
Filed under: , ,

[Advertisement]

Comments

Ben Scheirman wrote re: thinking out loud: asp.net mvc & nhaml
on 10-02-2009 5:17 PM

Your Html helper is basically duplicating what's available in ASP.NET MVC 2 Preview 1.  Check my article for more info on this (dotnetslackers.com/.../A-First-Look-at-ASP-NET-MVC-2.aspx) -- my guess is you'll be happy to delete code in favor of this built-in solution.

I really like the base class, and I've done this before as well.  It reminds me of rails and it's just more friendly.  I'd vote to be a tad more explicit on when you should render a 404 versus catching all InvalidOperationExceptions...

Corey wrote re: thinking out loud: asp.net mvc & nhaml
on 10-02-2009 5:23 PM

I would think that using NHaml would make it a maintenance nightmare. I agree it's compelling and nice to look at, but I'm convinced it would end up creating more work than it's worth. At least with spark it's close enough to standard html that the maintenance piece would be less of a concern. How does NHaml fit in with your vision of UX/IxD?

Christopher Bennage wrote re: thinking out loud: asp.net mvc & nhaml
on 10-02-2009 5:36 PM

The HandleUnknownAction() I took from this sample msdn.microsoft.com/.../system.web.mvc.controller.handleunknownaction.aspx (I forgot to credit that).

I agree with you about the 404.

... and yes, I would be happy to delete code in favor of something built in.

Christopher Bennage wrote re: thinking out loud: asp.net mvc & nhaml
on 10-02-2009 5:42 PM

@Corey yes, I'm struggling with how nhaml will work. A IxD designer would have to know nhaml, but that true for any view engine. Admittedly, nhaml is more idiomatic than others.  I think I may only know by giving it a serious try. (Or by paying very close attention to haml's community).

Regardless of view engine, my thoughts about UX/IxD and the web center more around semantic html, css, and jQuery. I think that nhaml _might_ be a good fit (enabler even) for semantic html.

I'll post soon about how the IxD thing played out in our work on silverarcade.com.  

Neal Blomfield wrote re: thinking out loud: asp.net mvc & nhaml
on 10-03-2009 1:44 AM

Treating a post as a command works well, that is how I have written the app I am currently working on.  Slight variations:

1/ All my parameter objects are actually defined by interfaces and I use a custom model binder to find them in a windsor container.  Makes testing your application flow insanely simple and very effectively separates controller from anything else ( significantly reducing controller constructor injection)

2/ My command implementation contain the logic to execute the task - effectively gives me a fine grained task based entry point into the domain.

Be wary of HandleUnknown - it will also fire if no action is found matching the verb codebetter.com/.../handleunknownaction-in-asp-net-mvc-be-careful.aspx.

Looks good, be keen to see where you go with this.

akuznetsov wrote re: thinking out loud: asp.net mvc & nhaml
on 10-03-2009 2:12 AM

"property.Compile().Invoke(model)"

.Compile() is not really good for your performance

As a matter of fact you're already have MemberInfo to use.

You may just write

((PropertyInfo)expression.Member).GetValue(model, null)

That should significantly improve performance.

brad wrote re: thinking out loud: asp.net mvc & nhaml
on 10-03-2009 2:16 AM

That method is cool, but watch out for that Expression.Compile() method, its a touch slow.

Christopher Bennage wrote re: thinking out loud: asp.net mvc & nhaml
on 10-03-2009 10:45 AM

Thanks! This is excellent advice.

Sanjeev Agarwal wrote Daily tech links for .net and related technologies - October 5-7, 2009
on 10-06-2009 4:24 AM

Daily tech links for .net and related technologies - October 5-7, 2009 Web Development How To Speed Up

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)

CodeBetter.Com