NHaml News

Posted by Andrew on July 29, 2008

A while back we moved the NHaml core templating engine out of the MVCContrib project. This was done so that the core stuff could be maintained separately and to declutter the contrib project.

NHaml now lives on Google Code .

As part of the move, I’ve added a small, stand-alone ASP.NET MVC View Engine that doesn’t require MVCContrib - useful for people not wanting a dependency on contrib.

Other changes since the move are:

- Added NHaml configuration support into the core - was previously in the view engine.
- Improved view activation performance using LCG.
- Rendered view output is now written to a provided TextWriter improving perf for view engines.
- Incorporated a simple view engine framework into core.

Enjoy,

Andrew.

Trackbacks

Use this link to trackback from your own site.

Comments

Leave a response

  1. Wed, 30 Jul 2008 08:20:11 CDT

    [...] to VoteNHaml News (7/29/2008)Tuesday, July 29, 2008 from andrewpeters.netAs part of the move, I’ve added a small, stand-alone [...]

  2. Wed, 30 Jul 2008 11:53:37 CDT

    This is awesome to hear, so I won’t need the contrib anymore at all to use NHaml? Also, when you say it improved performance does it help with the cold start issue? I still have some major lag when my app is hit the first time.

    Thanks for all your awesome work on this, let me know if you ever need any resources for it.

    -James

  3. AndrewNo Gravatar Wed, 30 Jul 2008 18:03:08 CDT

    Hi James,

    Correct, you can now use the built-in view engine or the one in contrib.

    Regarding performance, give this version a go and let me know how you get on. Happy to work through any issues you encounter - you can email me directly at andrew at mindscape.co.nz

    Cheers,

    Andrew.

  4. Thu, 31 Jul 2008 00:38:12 CDT

    Hi Andrew!

    Cool news.
    What do you think about combining our efforts?
    I could move my fork into your project. Only one thing bother me - lack of 2.0 support.

    Could we introduce conditional compilation or something else?

    Regards,

    Sergey

  5. AndrewNo Gravatar Thu, 31 Jul 2008 01:20:29 CDT

    Hi Sergey,

    Yes, I’m keen for conditional compilation too. But we need to do it without losing core haml functionality like attribute eval.

    I’m going to take a look at this tonight.

    Cheers,

    Andrew.

  6. Thu, 31 Jul 2008 01:34:22 CDT

    Hi Andrew,

    How are you using the attribute eval in real life? I quickly cast a look at samples (AttributeEval.haml) and it’s looks weird to me (especially string.Join)

    Thanks,

    Sergey

  7. AndrewNo Gravatar Thu, 31 Jul 2008 02:28:57 CDT

    Hi Sergey,

    That is just a contrived test scenario to test edge cases.

    Attribute eval is vital - Without it the view engine is severely limited because you can’t dynamically set attribute values. E.g. You want to highlight alternate rows in a table using a style.

    Cheers,

    Andrew.

  8. Thu, 31 Jul 2008 03:06:14 CDT

    Hi Andrew,

    Yes it make sense!
    though I can do this with silent eval and IFs.

    What do you think about generating “anonymous” type at runtime?
    What if template builder will add such a classes as inner types into view template class, then all of your magic with Attribute evals will work out!

    It’s not too complicated .

  9. AndrewNo Gravatar Thu, 31 Jul 2008 03:55:39 CDT

    Hi Sergey,

    NHaml already makes use of C# 3 anonymous type initializers to implement attribute eval - It works great but is obviously not going to work if we target 2.0.

    The real benefit of using anonymous types is that we get to hand off the _splitting_ of the key value pairs to the C# compiler. While superficially easy, this is actually hard as the right hand side of the attribute can be an arbitrarily complex C# expression.

    If we could split the attributes reliably then we wouldn’t need the anonymous types as we would just eval the right hand side.

    Cheers,

    Andrew.

  10. Thu, 31 Jul 2008 04:14:04 CDT

    Hi Andrew,

    This is exactly what I’m going to do.

    Cheers,

    Sergey

  11. AndrewNo Gravatar Sun, 03 Aug 2008 07:25:07 CDT

    Sergey,

    I got it working for .NET 2.0! - Latest revision here:

    The Monorail view engine should now be possible. Let me know if you have any issues.

    Cheers,

    Andrew.

  12. Mon, 04 Aug 2008 01:01:56 CDT

    Andrew,

    Cool. You overrun me :)

    hm. Parser, Scaner?

    Any performance test?
    Anonymous types performance are very impressive.

    I’ll about to commit MonoRail engine to your repository. Could you add me to Google Code?

    Regards,

    Sergey

  13. AndrewNo Gravatar Mon, 04 Aug 2008 03:13:30 CDT

    Sergey,

    Performance should be very good as input is generally small and Coco/R is very fast. There is more room to optimize the input grammar if required as we only need a subset of C#. What’s more, this approach is reliable.

    I’ve added you to the project on your cift.ru email address. If possible, please check out the project coding standards and ReSharper code formatting rules.

    Thanks,

    Andrew.

  14. AndrewNo Gravatar Mon, 04 Aug 2008 23:35:06 CDT

    Sergey,

    To follow up, a simple perf test shows version 2 compiler/coco compilation to be faster than 3.5!

    View rendering should also be faster as attribute value rendering is direct eval rather than anonymous type reflection property access.

    Cheers,

    Andrew.

  15. PhilNo Gravatar Thu, 07 Aug 2008 21:52:25 CDT

    Andrew,

    What would be the best way to incorporate other user interface frameworks with Haml and ASP.NET MVC? I am considering using either a set of pre-written partials or Html helper extensions. Some prototyping has been done to evaluate the use of Html helper extensions. The following is the only solution I have come up with to allow embedded Haml code within the helper extension calls.

    Am I missing the boat? Any feedback would be appreciated.

    The following code sample is a derivative of your sample application.haml file. It assumes that a library has been built to incorporate the Dojo framework.

    !!!
    %html{xmlns=”http://www.w3.org/1999/xhtml”}
    %head
    %title My Sample MVC Application
    %link{href=”../../Content/Site.css”, rel=”stylesheet”, type=”text/css”}
    %style{type=”text/css”}
    @import “http://o.aolcdn.com/dojo/1.0/dijit/themes/tundra/tundra.css”;
    @import “http://o.aolcdn.com/dojo/1.0/dojo/resources/dojo.css”
    %script{type=”text/javascript”, src=”http://o.aolcdn.com/dojo/1.0/dojo/dojo.xd.js”, djConfig=”parseOnLoad: true”}
    %script{ type = “text/javascript” }
    dojo.require(”dojo.parser”);
    dojo.require(”dijit.Tooltip”);
    dojo.require(”dijit.TitlePane”);
    dojo.require(”dijit.layout.LayoutContainer”);
    %body.tundra
    #inner
    #header
    %h1 My Store Manager
    #menu
    _ Shared\Menu
    = Html.LayoutContainer(”maincontent”)
    = Html.TitlePane(”tmain”, “This is the main site content”)
    _
    = Html.RenderCloseTag(”div”)
    = Html.RenderCloseTag(”div”)

    Thanks,
    Phil

  16. Igor LoginovNo Gravatar Wed, 13 Aug 2008 11:45:55 CDT

    Andrew,

    Latest releases tell that you are hardly working on NHaml performance now. Thank you!

    Let me ask you a question regarding recent changes in NHaml core. I try using NHaml in scenarios much more simple than ASP.NET MVC. So, let’s imagine I want to build a web page and dynamically insert a phrase “It took %d seconds to prepare data for this page” somewhere on it. WHat I did with NHaml 1.0 ? I created data class TestNHamlData with Timing property. Then I used the lines

    templateCompiler.ViewBaseType = typeof(TestNHamlData);
    Type viewType = templateCompiler.Compile(template, layout);
    ICompiledView view = (ICompiledView)Activator.CreateInstance(viewType);

    After some digging in code I knew that NHaml generates a class inherited from my TestNHamlData and implementing ICompiledView interface. Thus, view is an object of this class, and the following will work:

    TestNHamlData viewData = view as TestNHamlData; // thank to TestNHamlData inheritance
    viewData.Timing = elapsedTime;
    output = view.Render(); // thank to ICompiledView interface

    … and I am happy with up-to-date data in generated output.

    What is in new version? Instead of Activator there is TemplateActivator which is generic delegate for calling a dynamic method with Reflection.Emit inside. Much faster way of generation! But how to set my last-minute-data to generated object before rendering if ViewType with both base class and ICompiledView interface is not available anymore?

    I will greatly appreciate your comments.

  17. AndrewNo Gravatar Wed, 13 Aug 2008 16:39:36 CDT

    Hi Igor,

    Add a method such as this to your base class:

    public void Render(TextWriter outputWriter, int timing)
    {
    Timing = timing;

    ((ICompiledTemplate)this).Render(outputWriter);
    }

    Hope this helps,

    Andrew.

  18. PeterNo Gravatar Thu, 14 Aug 2008 14:47:52 CDT

    Hi Andrew,

    I downloaded your source, took out the NHaml.dll and NHaml.Web.Mvc.dll and referenced them in my MVC Preview 4 project. I also added the

    ControllerBuilder.Current.SetControllerFactory(new NHaml.Web.Mvc.NHamlControllerFactory());

    line to my Global.asax file. My app won’t build now (although it did before and does if I remove the references to the two DLLs). Did I miss something in the configuration process (web.config modifications maybe)?

    Great working! Look forward to

  19. AndrewNo Gravatar Thu, 14 Aug 2008 16:05:21 CDT

    Peter,

    Did you pull the latest source from Google Code? In there is a sample MVC project you can use as a starting point.

    Cheers,

    Andrew.

  20. PeterNo Gravatar Thu, 14 Aug 2008 18:57:29 CDT

    Yes I pulled the latest code via subversion. The sample MVC project compiles and my MVC project is set up but refuses to build (without displaying any reason for not doing so). I just wanted to make sure that those two steps were all that was required to get NHaml working?

  21. AndrewNo Gravatar Thu, 14 Aug 2008 19:58:24 CDT

    Peter,

    Yep, that should be it. What does your Output window say?

    Cheers,

    Andrew.

  22. PeterNo Gravatar Thu, 14 Aug 2008 22:39:57 CDT

    In the IDE nothing.
    If I run the compile statement in a command window I get the following:

    Microsoft (R) Visual Basic Compiler version 9.0.30428.1
    Copyright (c) Microsoft Corporation. All rights reserved.

    InternalXmlHelper.vb(9) : error BC30560: ‘ExtensionAttribute’ is ambiguous in th
    e namespace ‘System.Runtime.CompilerServices’.

    _
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    InternalXmlHelper.vb(24) : error BC30560: ‘ExtensionAttribute’ is ambiguous in t
    he namespace ‘System.Runtime.CompilerServices’.

    _
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    InternalXmlHelper.vb(39) : error BC30560: ‘ExtensionAttribute’ is ambiguous in t
    he namespace ‘System.Runtime.CompilerServices’.

    _
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    I’m using VS2008 with MVC Preview 4. My model uses Nhibernate.

  23. AndrewNo Gravatar Thu, 14 Aug 2008 23:08:11 CDT

    OK cheers. It looks like it’s because NHaml uses the Extension Method hack and the VB compiler doesn’t grok the duplicate definition. I’ll remove the use of extension methods as they aren’t essential in the core. As a workaround, you can remove NHaml’s definition of ExtensionAttribute and re-target NHaml to 3.5.

    Cheers,

    Andrew.

  24. PeterNo Gravatar Fri, 15 Aug 2008 08:08:29 CDT

    Hey Andrew,

    That did it. Many thanks for the quick helpful response and of course NHaml itself.

    Peter

  25. PeterNo Gravatar Fri, 15 Aug 2008 09:20:36 CDT

    Hi Andrew,

    One more question — in the original MVC the FooController would check the Views/Foo folder and then check the Views/Shared folder if it could not find a proper view. It appears that you’ve removed this behaviour to take advantage of Layouts? Is there any way to accomplish the default MVC behaviour as I share the same view across many controllers.

    If I have a view called PortfolioIndex.haml in the Shared folder, MVC can’t find it (File not found exception for Views\Portfolio\PortfolioIndex.haml)

    Peter

Comments