Click here to Skip to main content
Click here to Skip to main content

Introduction to Bellevue View Engine - Part 1

, 18 Mar 2010
Rate this:
Please Sign up or sign in to vote.
Prototype of a new template engine for ASP.NET MVC Framework that respects HTML and uses CSS-like syntax for model binding.
intro_picture.png

Introduction

Bellevue is a prototype of a new Open source template engine for ASP.NET MVC Framework. Bellevue uses pure HTML in its core - without any additional tags or syntax. It then uses CSS-like syntax to inject the active logic into the HTML - or in other words: to bind the data from the model to the view.

In this first part, I am covering the basics:

  • Design goals
  • The idea in brief
  • Roadmap
  • Getting Started in Visual Studio
  • Declarations
  • Relative positioning
  • Functions
  • Debugger

The second part is here and it goes into more advanced features and discusses the design and the future features I am planning.

Design Goals

The design goals of this new Template technology / View Engine are:

  • Respect HTML as a first-class language as opposed to treating it as "just text".
  • Don't mess with my HTML! The data binding code (Bellevue code) should be separate from HTML.
  • Enforce strict Model-View separation as described by Terence Parr here.

The Idea in Brief

Pretty much all existing template engines (MVC view engines) start from HTML, but then force the developers to modify this HTML to insert active content in the middle of the HTML.

For example in ASP.NET Web Forms, you add <% ... %> tags in places where you want the active content to be shown:

Asp.Net WebForms example

These modifications render the original HTML useless for many purposes: it can no longer be shown stand-alone in a web browser and most of the WYSIWYG editors can no longer show it properly.

Bellevue takes a different approach. It keeps the original structure of the HTML as-is:

Bellevue html example

... and then uses a separate CSS-like script to inject the active content within the HTML:

Bellevue script example

Bellevue View Engine is a fully ASP.NET MVC compatible view engine: It will support all features of ASP.NET MVC and you can mix it with Web Forms views and even with other view engines. It will be released as open source using some License, which I have not yet decided. I reserve the moral right to release additional tools or versions with commercial license, but the basic view engine will be free.

Roadmap

Warning - hacks ahead

Before we get deeper into code, let's get the expectations straight: This is a preview demonstrating the idea. Even though I am releasing the source code, the point of this article is to get some feedback about the idea - not really about the implementation.

If you are looking for something you can actually use in production, please check back in one or two months. I am about to start a major rewrite to fix the hack-level code and I should hopefully have a more production-level implementation in May-June timeframe.

With that disclaimer, let's dig into the code...

Getting Started in Visual Studio

All the following code is in the Ope.Bellevue.DemoWeb project in the downloads package.

To get started with Bellevue in a new Visual Studio ASP.NET MVC project, you need to first make the reference to "Ope.Bellevue.dll". Then, you need to add to your "Global.asax.cs" the registration of Bellevue view engine:

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);

    // Uncomment this line, if you are not using aspx pages / ascx controls at all.
    // ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new Ope.Bellevue.BellevueViewEngine());
}

Now you are ready to add a Bellevue view. View is just a HTML-file with .htm or .html suffix. The example here is "/Views/Demo/Demo1_Intro_Bellevue.html", which has the following HTML in the upper part of the body:

<div id="menucontainer">
    <h1>Info about <b>Product 1</b></h1>
</div> 

To change the "Product 1" text to ViewData["Name"] coming from the controller, we would add the following Bellevue script in the head part of the HTML file:

<script type="text/bellevue">
    h1 b        {   text: data(Name); }
</script>

Let's go through this: The script tag is just like a normal script tag according to HTML standard. Instead of type "text/JavaScript", we are using type "text/bellevue". This is a marker for the Bellevue parser to take the contents and apply that script to the HTML document on the server side. If the page is loaded without going through Bellevue view engine (e.g. directly from file system to browser), the browser will simply ignore a script where it does not recognize the type.

The syntax of the script is just like CSS: we have the selector "h1 b", which will select our target element and apply the declaration "text: data(Name)" to that element. Declaration "text" tells the system to replace the inner text with the value which in this case is function "data(Name)". This will return either ViewData["Name"] or ViewData.Model.Name.

The script can of course also be an include file like in "Demo2_Intro_Bellevue.html":

<script type="text/bellevue" src="Demo2_Intro_Bellevue.bvue"></script>

The include files must have the .bvue suffix, but the suffix can be left out from the src attribute. Include files are searched for like partial views, so they can also be in the Shared folder.

The selectors can be much more complex like in "Demo2_Intro_Bellevue.bvue".

#main table tr:nth-child(1) td:nth-child(2) {   text: data(Name);   } 

I am currently using the Fizzler CSS selector with HTML Agility Pack and the CSS parser is the one from BoneSoft here in code project. They all are great projects, but they have some limitations and bugs, so you do not get all the features of CSS Level 3 selectors. But a powerful set in any case.

Declarations

Just replacing text would not be that great, but of course there are also other declarations. This preview version has the following:

  • text: As above, note that the text is HTML-encoded
  • attr: Replaces the value of an attribute, attribute encoded
  • html: Replaces the inner HTML, not encoded
  • text-format: Applies given string formatting to an object
  • text-replace: Replaces specified text within the original inner text with a new text
  • checked: Sets the checked attribute of an input
  • style: Sets the style attribute
  • class: Sets the class attribute
  • value: Sets the value attribute
  • apply-template: See templates below
  • render-control: Renders a partial view
    • Can be a Bellevue partial view or ascx (or from any other properly implemented ASP.NET view engine)
  • action-link: The same as HtmlHelper.ActionLink() in Web Forms
    • This is a proto on how HTML helper methods can be used through Bellevue
    • I am planning to implement other helper methods too, but I need to go through all those overloads and think how it all makes sense.

To get more details on how you can use these declarations, see the "Declarations.html" view. There are some examples.

Relative Positioning

CSS selector will always match an individual element. By default, most declarations target the inner nodes (or inner HTML) of the element that was matched by the selector, i.e. p { text: "foo" } will replace the HTML inside <p>any html</p> to be <p>foo</p>.

Sometimes this is not quite enough, but you can get more control by using standard suffixes of declaration names:

  • -outer: Replaces the outer HTML of the element
  • -add: Appends a new node inside the element
  • -insert: Inserts a new node as the first child node in the element
  • -before: Inserts a new node just before the element
  • -after: Inserts a new node just after the element
  • -inner: Explicitly states to target the inner HTML. Added in case some declarations would not target inner HTML by default. May be removed in later versions.

For more information and examples, see "Demo5_RelativePosition.html" in the demo project.

Functions

We already used the "data()" function above, but there are of course others. The current implementation has the following set:

  • first(collection): The first or only item in the collection
  • last(collection): The last or only item in the collection
  • rest(collection): All, but the first item in the collection
  • trunc(collection): All, but the last item in the collection
  • strip(collection): The collection without null values
  • length(collection): The length of the collection
  • join(collection, separator): Concatenates all items in the collection
  • item(property path): Data object from the current item passed to a template
  • index(base): Zero-based index number of the current item adding the base number
  • get(container, property path): A property from any object
  • data(property path): Data from the ViewData object
  • model(property path): Gets data from the ViewData.Model object
  • concat(value1, value2, valueN): Concatenates string values
  • if(condition, value if true, value if false): Like ternary operator ("?") in C#
  • isnull(value, value if null): Like in SQL
  • false(): Boolean value false
  • null(): Null value
  • true(): Boolean value true

You can nest functions and much of them are the same as in StringTemplate. Most of the functions are probably obvious, but there is a reference in here - and it is also included in the demo Project.

Debugger

If you have checked any of the examples in the demo project, you have no doubt noticed that at the bottom of each page, there is the "Bellevue debugger". The debugger shows you possible warnings and errors, rule sets that are applied to elements and the contents of the model (limited implementation) and ViewData dictionary.

The debugger is now on by default, but if it bothers you, you can set it off by changing the Global.asax.cs:

var engine = new Ope.Bellevue.BellevueViewEngine();
engine.ShowDebugger = false;
ViewEngines.Engines.Add(engine);

This is of course just temporary implementation. In the final version, you should have much more control over the debugger, but at this stage you usually want to see the debug information.

Wait, There Is More...

So these are the basics. If this made you interested, Part 2 takes you through Templates and Master pages. The demos are already in this download project. I will also give some more information about the ideas for future development and talk about the design and implementation.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

OPerttilä
Founder OPE AG
Switzerland Switzerland
Olli is a .Net developer and architect.
 
He specializes in Asp.net MVC and other web technologies, XML and lately Domain Specific Languages.
 
Olli is originally from Finland, but currently works for his own one-man-initiative OPE AG (www.ope.ag) from Switzerland. He has over 10 years of experience as one of the founding partners and Chief Technology Officer of Quartal group of companies (www.quartal.com).

Comments and Discussions

 
GeneralGood work! Pinmembermaxscan26-Mar-10 0:36 
GeneralTypo PinmemberWes Aday18-Mar-10 12:05 
"filosofy" should be philosophy. Smile | :)
Why is common sense not common?
Never argue with an idiot. They will drag you down to their level where they are an expert.
Sometimes it takes a lot of work to be lazy
Individuality is fine, as long as we do it together - F. Burns
 
Help humanity, join the CodeProject grid computing team here

GeneralRe: Typo PinmemberOPerttilä18-Mar-10 13:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140709.1 | Last Updated 19 Mar 2010
Article Copyright 2010 by OPerttilä
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid