I was literally in the middle of writing the post when I saw a message from Andrew Davey about how he had implemented the same idea! Of course, his is way better, so I got to code via subtraction. That means subtracting out the crap I had written in a few minutes and dig into his code.
There are no unique ideas, right? ;) Either way, it's fun when the same idea is being thought about simultaneously.
Here's the general concept. A few weeks back I was talking with Avner Aharoni, a Language Program Manager, and he had been kicking around the idea of VB9's XML Literals making friendlier Views within ASP.NET MVC.
I've blogged about VB9's rocking sweet XML support before. It lets you create XML like this. Note the lack of strings...the XML is there in the language and the compiler and intellisense are all aware of it.
Dim books = <bookstore xmlns="http://examples.books.com"> <book publicationdate=<%= publicationdate %> ISBN=<%= isbn %>> <title>ASP.NET Book</title> <price><%= price %></price> <author> <first-name><%= a.FirstName %></first-name> <last-name><%= a.LastName %></last-name> </author> </book> </bookstore>
Starting with the Northwind ASP.NET MVC Sample Code for Preview 3 that Phil updated, let's look at the List View:
<asp:Content ContentPlaceHolderID="MainContent" runat="server"> <h2><%=ViewData.CategoryName %></h2> <ul> <% foreach (Product product in ViewData.Model.Products.Model) { %> <li id="prod<%= product.ProductID %>"> <%= product.ProductName %> <span class="editlink""> (<%= Html.ActionLink("Edit", new { Action="Edit", ID=product.ProductID })%>) </span> </li> <% } %> </ul> <%= Html.ActionLink("Add New Product", new { Action="New" }) %></asp:Content>
This is straight from the ASPX page with inline C#.
Now, we thought it'd be cool/interesting/potentially-something if we could use the XML Literal support to get, as Andrew puts it "compiled, strongly typed, intellisense friendly views." Sure, we mostly get that with the ASPX pages, but perhaps this would be better/easier/something? Keep in mind here that we're playing.
Your opinions on if this is a good idea or something to move forward would be useful. Leave comments and I'll compile and give them directly on to the VB and MVC team(s)! Remember, it can look like however you think it should, so don't be constrained by my spike or Andrew's.
Here's why Andrew thinks it's cool, quoted from a post on the ALT.NET mailing list:
Some key features I've used. - <%= From ... Select ... %> to create repeated elements - VB's ternary "If" operator for conditional output - X-linq to post process the HTML before sending it - choose between indented and compressed XML output - modules of functions as "controls" - it's so simple :)
Here's what my solution looks like in Visual Studio. See how the ListVB.aspx has no "+" sign. There's no code-behind .cs file there even though this is a C# project. The meat of the View is in another assembly (although you could conceivably do something freaky and get VB and C# to live in the same assembly (be sure to read the comments)).
Actually, the ListVB.aspx file is VB, not C# and refers not to to a code-behind, but another class in another DLL, specifically the VBViews assembly.
<%@ Page Language="VB" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" Inherits="VBViews.ListVB" Title="Products" %><%@ Import Namespace="NorthwindModel" %><%@ Import Namespace="System.Collections.Generic" %><asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server"> <h2><%=ViewData.Model.CategoryName%></h2> <% = GetList() %></asp:Content>
Here's the Visual Basic code in the other assembly.
Imports System.Xml.LinqImports NorthwindDemo.ModelsPartial Public Class ListVB Inherits System.Web.Mvc.ViewPage Function GetList() As XElement Dim c As Category = CType(ViewData.Model, Category) Return <ul><%= From product In c.Products _ Select _ <li id=<%= "prod" & product.ProductID %>> <span class="editlink"> <a href=<%= "/Products/Edit/" & product.ProductID %>> <%= product.ProductName %> </a> </span> </li> %> </ul> End FunctionEnd Class
This won't really be clear without some syntax highlighting to make the point, so here it is again, but this time as a screenshot. See now the VB code, XML and <% %> blocks are all together in same line? VB is just generating XElement's which in turn will turn into a string when "rendered" by the ASPX page.
Andrew Davey's NRest project is more than just VB9 Views. It's a REST web framework for ASP.NET using the Nemerle programming language (using the May CTP). You can browser or GET his code with SVN here: http://svn.assembla.com/svn/nrest/trunk/. It's also a nicely laid out solution that uses the Ninject IOC but I'll cover that later. Do check out Andrew's screencast about his NRest project.
His code is a mix of C#, Nemerle and VB. The Website, Tests and Services are in C# and the Ninject modules are in Nemerle, along with the meat of the main NRest project. I think he could have used more of System.MVC, specifically the View Engines, that he did, but I'm still grokking his intent.
He's got a hierarchy in VB with a MainPageBase, Page, in order to achieve a kind of Master Pages:
Public Class MainPageBase(Of TChrome As MainChrome, TContent) Inherits Page(Of TChrome, TContent) Public Overrides Function GetHtml() As XElement Return _ <html> <head> <title><%= Chrome.Title %></title> <link href="/styles/demo.css" type="text/css" rel="Stylesheet"/> <%= GetHeadContents().Elements() %> </head> <body> <h1><%= Chrome.Title %></h1> <%= GetBodyContents().Elements() %> </body> </html> End Function Public Overridable Function GetHeadContents() As XElement Return <_></_> End Function Public Overridable Function GetBodyContents() As XElement Return <_></_> End FunctionEnd Class
So a Hello World page in VB would be very simple, just this:
Public Class CustomerPage Inherits MainPageBase(Of CustomerPageData) Public Overrides Function GetBodyContents() As XElement Return _ <_> <p>Hello <%= Content.FirstName & " " & Content.LastName %></p> </_> End FunctionEnd Class
All of this is a work in progress, but it's really cool that we're all trying to push the envelope and not afraid to try crazy stuff in order to make things better. It'll be cool for me to read this post in a year and either say "ew" or "cool!" depending on what direction we all went.
Have you done anything cool or crazy with Views and ViewEngines, Dear Reader?
Related Posts
Ads by The Lounge