Separating html and logic in Razor (WebPages or Umbraco macroscript)

Standard

Mixing logic and html can easily end up with messy, hard-to-maintain code. In MVC it’s easy to separate the parts with the controller / view-separation. But how to do it nicely in WebPages or in an Umbraco macroscript?

Ultimately I want my Razor to be free from

  • variable assignments other than for loop iterators
  • function calls other than formatting and html helpers
  • usage of data outside of the “ViewModel”

I have some WebPages and Umbraco projects with some quite advanced razor code and I’ve been having many doubts about how I mix logic in my razor code. I try to separate it, most often by placing logic at the top, but still using Razor (with helpers or RenderPage by all means). After re-thinking some about the @functions ability in Razor and found out about the overridable InitializePage function I feel I now have a better more solid structure to use.

Update: I recommend do not use this too extensively
The “functions” approach is nice, but also consider the simpler way just to have an initialization section in the top of the script – still separating C# from actual view. See this post for an example.

And if you have extensive pure C# move it to a base class which you inherit your script from.

The idea is simply this : remove all logic (but necessary iterations and some conditions) from the razor, and place it in the @functions part (in the InitializePage function) together with ViewModel properties. The ViewModel properties should contain all data that the view part needs to be able to render the page / the macro. And the view part should not access anything else than the ViewModel properties:

@* --- The logic-less view part: --- *@

<p>@SomeProperty</p>

@* --- The controller / viewmodel constructor part: --- *@

@functions{

  // the properties of the view model:
  public string SomeProperty {get; set;}

  // taking care of post data and constructing the view model:
  protected override void InitializePage()
  {
    // make up the "ViewModel" properties
    SomeProperty = "some data";
  } 
}

Advantages with this approach

  • A clear separation of view and logic (not as clear as having them in separate files tho)
  • The logic is pure C#-code, no risk of doing mistakes due to misplaced @’s (and missing code blocks)
  • The code is a big step towards MVC, and the full step will be quite easy later on if necessary
  • Minimal added whitespace in page source

Helpers are perfectly fine to add to this – but just as with the view code, I think any logic but view logic should be left out of them.

A remake of my “old skool” contact form sample

I wrote a contact form razor sample quite a while ago, guilty of mixing logic into the view. However I’m not the only one ;), a sample at asp.net.

Here’s a better (I think) remake, using the initializepage-structure:

<h2>Contact form</h2>

@if(ShowMessage)
{
   <div><strong>@Message</strong></div>
}
@if(ShowForm)
{
   <form action="#" method="post">
     <div>
       <label for="name">Name:</label>
       <input id="name" name="name" value="@PostedName"/>
     </div>
     <div>
       <label for="message">Message:</label>
       <textarea id="message" name="message">@PostedMessage</textarea>
     </div>
     <input type="submit" value="Post message"/>
 
   </form>
}


@functions{
  public bool ShowForm {get; set;}
  public bool ShowMessage {get; set;}      
  public string Message {get; set;}
  public string PostedName {get; set;}
  public string PostedMessage {get; set;}
           
  protected override void InitializePage() 
  {
    base.InitializePage();
    if (!IsPost) 
    {
       ShowForm = true;
       ShowMessage = false;
    }
    else
    {
       PostedName = Request["name"];
       PostedMessage = Request["message"];
       var IsValid = (!string.IsNullOrEmpty(PostedName) &amp;&amp; !string.IsNullOrEmpty(PostedMessage));
       if (IsValid)
       {
         var bodyText = "Message from " + PostedName + Environment.NewLine + PostedMessage;
         umbraco.library.SendMail("from@mysite.com","admin@mysite.com","New message", bodyText,false);
         Message = "Thank you " + PostedName + " for posting a message";
         ShowForm = false;
         ShowMessage = true;
       }
       else
       {
         Message = "You need to enter both name and message";
         ShowForm = true;
         ShowMessage = true;
       }
    }
  }
}

Public properties or private fields?
The public properties could be private fields without any problem (in these samples), the reason I choose public properties is that I like to resemble the MVC structure as far as possible.

Responding to an ajax-post

This structure also makes it really easy to handle and respond to ajax posts to the same form (this can only be done in a pure WebPages razor, not Umbraco macro as that does handle the Response output the same way) :

    ... in the validated post part ...
    if (IsAjax)
    {
        Json.Write(new {
          postValid = true,
          message = Message
          }, Response.Output);
    }

In Umbraco the options for ajax are to either to run razor script outside of the Umbraco context (use WebPages + add reservedpath in web.config) or to make a separate “ajaxresult-template” with a razor call:

Bonus: posting the form with ajax in Umbraco

Using this method you can return json directly from your razor script in Umbraco. The tricky part is we dont want to return the surrounding template parts, and for simplicity we want to use code in the same razor script as as we already are in.

Add a template – call it AjaxRazor – which will be responsible for rendering the razor without anything but the script result (we add an if IsAjax condition to have some kind of security against unintended run script files, please add more security checks for posts on a live site):

<%@ Master Language="C#" MasterPageFile="~/umbraco/masterpages/default.master" AutoEventWireup="true" %>

<asp:Content ContentPlaceHolderID="ContentPlaceHolderDefault" runat="server">
  <umbraco:macro language="cshtml" runat="server">
    @if (IsAjax){
      var path = Request["path"];
      if (!path.StartsWith("~")) { path = umbraco.IO.SystemDirectories.MacroScripts + "/" + path;}
      @RenderPage(path)   
    }
  </umbraco:macro>
</asp:Content>

Now it’s possible to run any razor script using the url /AjaxRazor?path={path-to-script}

Next make the form post it’s contents to the template, with the razor script path as a querystring parameter, we get that path with the help of the page property VirtualPath:

@if(showOnlyJson)
{
  Json.Write(json, Response.Output);
}
else 
{
 if(showForm)
 {
 <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.min.js"></script>
 <script type="text/javascript">
  $(document).ready(function() {
  $('form').submit(function() {
  $.post('@ajaxPostPath', 
      $(this).serialize(), 
      function(data){
         alert(data);
      });
  return false;
 });
 });
 </script>

 <form method="post" action="#">
 <input type="text" name="name"/>
 <input type="submit"/>
 </form>
 }
 if (showMessage)
 {
   <p>@message</p>
 }
}
@functions{
 private bool showOnlyJson;
 private bool showMessage;
 private bool showForm;
 private string message;
 private object json;
 private string ajaxPostPath;
 protected override void InitializePage()
 {
   if(IsPost)
   {
      var postedName = Request["name"];
      message = "Thanks for posting";
      if (IsAjax)
      {
       showOnlyJson = true;
       json = new {message=message, name = postedName};
      }
      else
      {
       showMessage = true;
       showForm = false;
      }
   }
   else
   {
       showForm = true;
       ajaxPostPath = "/AjaxRazor?path=" + VirtualPath; 
   }
 }         
}

Umbraco v5

I believe this approach still might be useful in Umbraco v5. It should likely not be recommended as an option for advanced solutions, but for simple forms (and advanced navigations) I think its suitable. And even if it’s not suitable it’s a good step towards controllers and viewmodels.

A Razor application within an Umbraco site (notes from a current project)

Standard

We’re in the middle of re-developing a web application that previously was made as an asp.net Webforms app. The current requirements is to integrate the application into an Umbraco 4.7 site, to use a new design (delivered as a html, CSS & js prototype) as well as to change some of the underlying database workings.

We decided to go for an asp.net WebPages, aka Razor, aka WebMatrix, solution in this case. It’s a very straight forward, close to the metal, way of coding for the web, and we’re very happy with our experiences so far.
When we develop the application we work completely outside of Umbraco, within an Asp.Net Razor website in Visual Studio (and sometimes in WebMatrix actually). The application itself is completely independent of Umbraco context.

So, we test run and debug our application within Visual Studio, then we deploy all changes just by FTP’ing the files to the Umbraco staging site where our customer can try it within their site. It’s a very fluent and flexible developing process.

The most important parts of the application

  • A set of (~10) cshtmls that represents each different page (url) of the application.
  • A wrapper content page in Umbraco for each of the app pages, with the path to It’s corresponding cshtml as a property, RenderScriptPath.
  • A wrapper template in Umbraco, which is a copy of the standard content template for the whole site, but with one important instruction:
    <umbraco:macro runat="server" language="cshtml">
    @if(Model.RenderScriptPath!="") {
       @RenderPage(Model.RenderScriptPath)
    }
    </umbraco:macro>

    this call is rendering the actual application page within the site layout.

  • A service cshtml for serving Ajax calls
    @if (OurApp.CheckLogin() && IsAjax)
    {
      
      // routing each call to the right function / json result
    
      var action = Request["action"];
      if (action=="products") {
        var category = Request["category"];
        Json.Write(OurApp.ProductsByCategory(category),Response.Output);
      }
    }
  • A corresponding – empty – template with just this code to render the service cshtml:
    <umbraco:macro runat="server" FileLocation="/macroscripts/ourapp/ajaxservice.cshtml" />
  • An UmbracoMockLayout.cshtml to make the off-site app look nice, with references to the necessary CSS, images and JavaScript files
  • An _PageStart.cshtml to automatically use the above layout from each of our .cshtml-pages. We do not copy the _PageStart-file to the Umbraco site (and even if we did it would not be run).
    @{Layout = "_UmbracoMockLayout.cshtml";}
  • Businesslogic, in a separate project
  • PetaPoco, as the micro Orm layer for the database
  • JavaScript, CSS and image files. In the same paths in the separate project as in the Umbraco site
  • Dewd, as a way for our Umbraco editors to edit some datatables directly within Umbraco

Umbraco content and asp.Net membership

The application is not entirely disconnected from Umbraco (but almost). There are texts on a few of the pages that is editable from within Umbraco, and used with the common Model.Property syntax. Otherwise the application is just using the Umbraco site navigation and designs. Also the app is using the same membership as the site.

Conclusion

In this project we’re using techniques and products we really like and find to be very efficient and high quality. The resulting application is soon to be launced, so we cannot say much about how it ends up :-), but it’s looking good so far, and we can definitively say that the development process has been unusually friction-free and fast.

Från noll till en komplett webbplats med Umbraco CMS på mindre än en timme

Standard

Umbraco är ett gratis opensource-CMS byggt på Microsofts ASP.NET ramverk. Det är byggt för att vara lätt att förstå och använda, samt enkelt att bygga ut. Det är ett av de 3 mest populära nedladdade programvarupaketen i Microsofts Web Platform Installer och det används över hela världen för i stort sett alla typer av webbplatser.

Genom att använda gratisverktyget WebMatrix så är det väldigt smidigt att installera Umbraco på din dator – och det finns dessutom webhotell som erbjuder billig hosting för WebMatrix-sajter med mycket enkel publicering. Detta innebär att du kan ha en egen webbplats med de smidiga redigeringsmöjligheter som ett professionellt CMS erbjuder uppe och igång ute på internet på mindre än en timme.

Tror du mig inte? Häng med…

1. Ladda ned och installera WebMatrix

Gå till http://www.microsoft.com/web/webmatrix/ och installera den senaste versionen av WebMatrix.

2. Skapa en Umbraco webbplats från WebMatrix “Web Gallery”

När du startar WebMatrix får du som alternativ att starta en ny webbplats från “Web Gallery”. I galleriet hittar du Umbraco. Välj det och skriv in ett namn för din webbplats, följ sedan guiden för att ladda ned och installera Umbraco:

3. Kör Umbraco-installationen

När WebMatrix har installerat Umbraco kommer du att återgå till redigeringsdelen i WebMatrix. Klicka på länken till din webbplats (site) “URL : http://localhost:nnnn&#8221; för att öppna din lokala webbplats i din webbläsare:

Första gången du öppnar din lokala webbplats kommer Umbraco att köra sin installationsrutin. Där väljer du vilken typ av databas du vill använda, samt det användarnamn och lösenord du vill ha, dessutom får du om du vill välja “Starter kit” och “Skin” för din webbplats.

Jag rekommenderar dig att följa installationsrutinens föreslagna alternativ när sådana finns, välj således Sql CE som databas, det innebär att du inte behöver någon installerad databasserver på din dator, Sql CE använder helt enkelt en fil som kommer att sparas i din webbplats filstruktur.

När du får välja Starter kit och Skin föreslår jag att du väljer “Simple Starter kit”, och det Skin som du själv tycker bäst om.

4. Dags för det administrativa gränssnittet i Umbraco

När Umbracos installationsrutin är färdig så är det dags att titta på Umbracos användargränssnitt för första gången.

Lägg märke till att du har en trädvy med en “nod” för varje sida på din Umbracowebbplats. Klicka till att börja med på noden “Sample website” som representerar webbplatsens startsida. Ändra på några texter. När du har ändrat och vill att ändringarna ska synas så ska du klicka på Publicera (Publish). Då kommer din lokala sajt att uppdateras och du kan se webbplatsen med dina ändrade texter:

Det är enkelt att växla fram och tillbaka mellan Umbracos användargränssnitt och din webbplats med hjälp av webbläsarens flikar. Om du tappar bort din Umbraco-flik så kan du alltid öppna den igen genom att öppna adressen http://localhost:nnn/umbraco/ (när nnn är det portnummer som WebMatrix har valt åt dig, du hittar det under Site i WebMatrix).

Du har nu WebMatrix och din webbplats på din egen dator och det finns ingen möjlighet att komma åt den utifrån. Webbplatsens filer finns din mapp “Mina dokument” och undermappen “My Sites”. När du har stängt WebMatrix kan du komma åt din webbplats igen genom att öppna WebMatrix och sedan välja din webbplats under “My Sites”.

5. Ut med webbplatsen på internet

När du har redigerat din webbplats och vill att den ska synas på internet så behöver du hitta ett webbhotell (webbhost).

Du kan göra det med hjälp av en länk i WebMatrix, under Publish – Find Hosting, eller använda ett webbhotell som du känner till sedan tidigare.

Jag testade “Appliedi” när jag skrev den här artikeln. Deras installation var väldigt enkel med stöd för funktionen WebDeploy. Appliedi är dessutom gratis i tre månader (därefter $5 i månaden).

När du har beställt testpaketet ska du få ett epostmeddelande med dina inloggningsuppgifter.

Kopiera dessa uppgifter och klistra in dem i WebMatrix “Publish Settings”

6. Publicera!

När du har lagt in dessa uppgifter så kan du publicera din webbplats, klicka på “Publish”. Det kommer att ta några minuter eftersom en fullständig Umbracoinstallation innehåller ganska många filer. När publiceringen är klar kommer du – och alla andra – att komma åt din sida på Internet!

Att redigera innehållet

Både din lokala installation och den på ditt webbhotell har allting som behövs både för att visa webbplatsen och för att redigera den med Umbracos administrativa gränssnitt. Förutom publiceringsrutinen så finns det ingenting som kopplar ihop din lokala installation med den som finns på Internet. Det innebär att om du ändrar innehåll lokalt så kommer det inte att synas utåt om du inte publicerar om webbplatsen. Men det innebär också att du kan använda din lokala kopia för att testa olika idéer, och sedan lägga in dem på din publika webbplats när du är nöjd med resultatet, helt enkelt genom att jobba i det administrativa gränssnittet där också.

På samma sätt som att din lokala kopia är åtkomlig via localhost://nnn/umbraco/ så kommer du åt din webbplats på internet genom att gå till adressen http://www.mysite.com/umbraco/ . Inloggningsuppgifterna är desamma som du valde när du gjorde umbracoinstallationen.

Lycka till!

Läs mer om Umbraco på http://www.umbraco.org och om du har frågor eller kommentarer så får du gärna ställa dem här. Om det finns intresse så kommer jag återkomma med fler artiklar på svenska om Umbraco.

Jag kan också varmt rekommendera Umbraco-forumet.

The MvcMiniprofiler nuget in WebMatrix (WebPages) [5 minutes]

Standard

The MVC3-guys gets a lot of fun tools, but what about us that sometimes prefer WebPages for getting things done on the web? Mostly it’s cool since we’re on the same good solid Asp.Net platform. The MvcMiniProfiler for example. I just read Scott Hanselman’s introduction to it and wanted to try on a WebPages site. It worked fine and looks very useful – easily profile the server side of any WebPages web app.

First – create a new Web Site (Razor) in Visual Studio or create a new site from template in WebMatrix and choose the StarterSite template.

Then add the MvcEasyProfiler Nuget MiniProfiler by opening the Package Manager Console in Visual Studio (Tools-Library Package Manager, Install-Package MiniProfiler). Or start your site in WebMatrix and go to the _admin page, first create a password, and then search for MiniProfiler (choose Default(all) as source for packages). Look for the most recent version (1.6 today). Install it.

Next add a new file called _PageStart.cshtml in the root of your web site. That page runs for every page request on your site. Using the RunPage() we divide code to be run before and after page code execution. Add the following code:

@{
    if (Request.IsLocal)
    {
        MvcMiniProfiler.MiniProfiler.Start();
        RunPage();
        MvcMiniProfiler.MiniProfiler.Stop();
    }
}

Then open the _SiteLayout.cshtml page. Add the following code just above the head end tag to include the necessary js scripts on your pages:

...
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>    
    @MvcMiniProfiler.MiniProfiler.RenderIncludes()
</head>

After that you have the profiler running and you can test it by opening any page.

When you like to test a particular piece of code enclose it within a profiler step like this:

@using MvcMiniProfiler
@{  
    using (MiniProfiler.Current.Step("Doing complex stuff"))
    {
        Layout = "~/_SiteLayout.cshtml";
        Page.Title = "Welcome to my Web Site!";
    }
}

And you get a nice window top left on your page with profiling data:

Read the Hanselman post to dive deeper into the possibilities.

A first look at SlickGrid with read, insert and update (in WebMatrix)

Standard

A few days ago I had a quick look at Flexigrid and I planned to continue with it to enable updates. However when I searched a bit further I got recommendations to use SlickGrid instead and so I did. As with my Flexigrid post this post is based on what I learned in a short time – if you are looking for a in depth / best practices sample you should indeed look at the library authors samples instead.

My first impression with SlickGrid is that it is a very good looking grid and it was easy to get a read and update solution up and running with very little code.

Another strength of SlickGrid is that it is possible to use a DataView model to handle the data. However that’s not something I have experimented with yet, and this sample is using a straight serverdata – grid path.

Edit (2011-12-12) to make it use the latest SlickGrid I updated my code pretty much + now also allows insert (so full CRUD, yay…)

Here’s how I did it:

The data comes from a simple Sql CE 4 db-table with the columns id (pk+identity), name (nvarchar 100), description (nvarchar 100) and somevalue (int). To create the SlickGrid I initialize it with a columns array, an options object, a data.cshtml that returns a Json object from a database read and takes post data for database insert or update.

Here’s how the html & javascript code looks like for my page (default.cshtml):

@{
    Layout = "/_layout.cshtml";
}        
        <script type="text/javascript">
    $(document).ready(function () {
        var grid;
        var columns = [
		
            { id: "name", name: "Name", field: "name", editor:TextCellEditor, resizable:false, width:100, rerenderOnResize:true},
            { id: "description", name: "Description", field: "description", editor:TextCellEditor, resizable:false, width:100, rerenderOnResize:true},
            { id: "somevalue", name: "Some value", field: "somevalue", editor:IntegerCellEditor, resizable:false, width:100, rerenderOnResize:true},
            { id:"id", name:"Delete", field:"id",
              formatter: function (r,c,id,def,datactx) {
                  return "<a href='#' onclick='removeClick(" + id + "," + r + ")'>x</a>";
            }}
	    ];

        function removeClick(databaseId, gridRow) {

            $.post("data/delete/",{id:databaseId});
            var data = grid.getData(); 
            data.splice(gridRow, 1);
            grid.setData(data);
            grid.render();

        }


        var options = {
            editable: true,
			enableAddRow: true,
			enableCellNavigation: true,
			asyncEditorLoading: false,
            enableColumnReorder: false,                        
            autoHeight: true
        };


        // Handle updates

        $.getJSON("/mygrid/data", success = function (data) {
            grid = new Slick.Grid("#myGrid", data, columns, options);            
            grid.onCellChange.subscribe(function (e, args) {
                if (typeof(args.item.id)=='undefined')
                    $.post("/mygrid/data/insert", args.item);
                else
                    $.post("/mygrid/data/update", args.item);
            });
            
            // Handle new row
            
            grid.onAddNewRow.subscribe(function(e, args) {
                var item = args.item;
                var column = args.column;
                grid.invalidateRow(data.length);
                data.push(item);
                grid.updateRowCount();
                grid.render();
            });
            
            $("#myGrid").show();
        });
        
    });
</script>

<div id="myGrid" style="width:400px;display:none;"></div>

The page is using jQuery and SlickGrid with editors plugin (included in the library samples). The css is both from jQuery UI and from SlickGrid.

Here are all the js- and css- files that’s included in the header section of the page (_layout.cshtml):

<!DOCTYPE html>

<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title></title>
        <link rel="stylesheet" href="/js/slickgrid/slick.grid.css" type="text/css" media="screen" charset="utf-8" />
        <link rel="stylesheet" href="/css/smoothness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen" charset="utf-8" />
        <link rel="stylesheet" href="/css/examples.css" type="text/css" media="screen" charset="utf-8" />
        
		<script src="/js/jquery-1.7.min.js"></script>
		<script src="/js/jquery.event.drag-2.0.min.js"></script>

        <script src="/js/slickgrid/slick.core.js"></script>
        <script src="/js/slickgrid/slick.editors.js"></script>
        <script src="/js/slickgrid/slick.grid.js"></script>

        
    </head>
    <body>
        @RenderBody()
    </body>
</html>

The data.cshtml:

@{
    
    // Get Action from Url f ex /mygrid/data/insert /mygrid/data/update
    var action = UrlData[0];
    var db = Database.Open("data");
    
    if (IsPost)
    {        
        
        // Get Post data (convert null's to string or integer)
        
        var id = Request["id"];
        var name = Request["name"]??"";
        var description = Request["description"]??"";
        var somevalue = Request["somevalue"].AsInt();
        
        if (action=="insert")
        {                        
            var sql = @"INSERT INTO item (name, description, somevalue) VALUES (@0,@1,@2)";
            db.Execute(sql,name,description,somevalue);
            var newId = db.GetLastInsertId();
            Response.Write(Json.Encode(newId));
        }
        else if (action=="update")
        {
            var sql = @"UPDATE item set name=@1, description=@2, somevalue=@3 WHERE id=@0";
            var data = db.Execute(sql,id,name,description,somevalue);
        }                
        else if (action=="delete")
        {
            var sql = @"DELETE FROM item WHERE id=@0";
            var data = db.Execute(sql,id);
        }                
    }
    else
    {        
        var sql = "SELECT id, name, description, somevalue FROM item";
        var data = db.Query(sql).ToList();        
        Response.Write(Json.Encode(data));
    }       

}

A first look at Flexigrid (using it with WebMatrix and Json)

Standard

We all need a nice grid to display data from time to time. I found out at Stackoverflow that Flexigrid has some popularity and the images I saw of Flexigrid in action impressed me.

This is a brief introduction post describing a way to use it for basic display of data in a WebMatrix (WebPages) web site. (I soon need the update functionality, and I hope I’ll be able to try that out and blog about in a few days.)

Let’s say we have a datatable with the columns id, name and address. We can retrieve the data with the standard WebMatrix.Data library and display it with the WebGrid helper this way:

@{
  var db = Database.Open("myConnection");
  var sql = @"SELECT * FROM items";
  var data = db.Query(sql)
  var grid = new WebGrid(data);
}
@grid.GetHtml()

It works, but is not exactly pretty:

If we use Flexigrid instead we get a much nicer result:

To accomplish this we need the flexigrid js and css files from the Flexigrid site.

I downloaded the zip, and extracted the two folders js and css to the root of my web site. Then I added reference to them and to jQuery in my demo page:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Flexigrid demo</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script src="js/flexigrid.pack.js"></script>
    <link href="css/flexigrid.pack.css" rel="stylesheet" type="text/css" />
</head>

The Flexigrid needs an empty table tag and is initialized with a javascript function – together with information about the data columns, behaviours and looks of the grid.

I used a Flexigrid-sample and only changed it slightly to handle my columns (id, name, address) + the url for fetching the data.

The code is pretty self explanatory:

<table id="flex1" style="display: none">
</table>
<script type="text/javascript">
    $("#flex1").flexigrid({
        url: '/data.cshtml',
        dataType: 'json',
        colModel: [
            { display: 'id', name: 'id', width: 40, sortable: true, align: 'center' },
            { display: 'name', name: 'name', width: 180, sortable: true, align: 'left' },
            { display: 'address', name: 'address', width: 120, sortable: true, align: 'left' }
            ],
        searchitems: [
            { display: 'name', name: 'name' },
            { display: 'address', name: 'address', isdefault: true }
            ],
        sortname: "name",
        sortorder: "asc",
        usepager: true,
        title: 'Names',
        useRp: true,
        rp: 15,
        showTableToggleBtn: true,
        width: 700,            
        height: 200
    });

Fetching the data from
The data is being fetched with the help of an Ajax call, the url is specified in a parameter as in the code above. The data format is prefferably Json.

The Json needs to follow this format:

{total:1,page:1,rows:[{id:1,cell:{id:1,name:"c#",address:"test"},{id:2,cell:{id:2,name:"vb.net",address:"test2"}]}

To construct the actual Json I added a data.cshtml file, where I’m using the WebMatrix Json helper over an anonymous object like this (the code here also includes paging functionality):

@{
    var db = Database.Open("myConnection");
    var sql = @"SELECT * FROM items";
    var data = db.Query(sql).ToList();

    var pageLength = 15;
    var page = Request["page"].AsInt();   
    if (page==0) {page = 1;}

    var flexiGridItems = new
    {
        total = data.Count,
        page = page,
        rows = from n in data.Skip(pageLength*(page-1)).Take(pageLength)
               select new { id = n.id, cell = n }
    };

    var json = Json.Encode(flexiGridItems);
    Response.Write(json);
}

That is all that’s necessary to get the nice Flexigrid up’n running in a WebMatrix (WebPages) web site.

In my next blog post I will explore the data updating functionality of Flexigrid.

Happy coding!

A first take on a C# HtmlFormHelper with client and server side validation

Standard

I have been looking for a pretty basic way of automating creation of Html Forms from C#. There’s ofcourse the MVC-way with scaffolding. But I’m not happy with that. I want to easily create my html tag setup in code and add / edit the fields and validation rules in a DRY way. If someone knows of an existing project of this kind, please let me know.

EDIT : HtmlFormsHelper has evolved into “DynaForms” (repo at GitHub), I will be blogging about it soon.

(A complete rewrite of this approach I made before.)

Also read the followup CRUD sample together with NancyFx and SisoDb.

So I wrote a ~300 Loc’s helper class with which this code is all that is necessary to create basic form which maps to a poco:

@using HtmlFormHelpers
@functions{

    // Define the class somewhere
    public class MyClass
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Nickname { get; set; }
        public string EmailAddress { get; set; }
    }
}
<style type="text/css">
    div.labelinput, div.submit {clear:both;}
    .labelinput label {width:100px;display:block;float:left;}
    .labelinput input {width:200px;display:block;float:left;}        
</style>
@{

    // initiate the form helper object

    var form = new HtmlFormDescriptor("myclass-form");

    // Add some fields with optional validation rules, the helper will map the field names to the model field names

    form.Add("Name", required: true);
    form.Add("EmailAddress", labelText: "E-mail address", required: true, email: true);
    form.Add("Submit", type:"submit");

    // instantiate the model class

    var myClass = new MyClass();
    string view="";
    
    if (IsPost)
    {

        // update and validate the model

        var validationResult = form.TryUpdateModel<MyClass>(Request.Form, ref myClass);
        if (!validationResult.IsValid)
        { 
            view = form.Html(myClass);
        }
        else
        { 
            // the model is valid - proceed with it to a db or whatever
            view ="<div>Valid!</div>";
        }
    }
    else
    {
        view = form.Html();
    }    
}
@Html.Raw(view)

@* To enable client side validation using jQuery validate - just add librefs + one row: *@

<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.5.2.min.js"></script>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.8/jquery.validate.min.js"></script>

@Html.Raw(form.ClientSideScript())

Here’s a demo

Here’s the full source

Mind it’s still an early version and it’s far away from perfect, I publish it as I hope I can get comments, ideas and collaboration if someone is up to it. It’s easy to create a Gist fork and publish your own version of this little thing.

HtmlFormHelpers Gist

In my previous version I used FluentValidation for the server side validation, it’s still easy to use that instead of my simple validation code, but I missed a nice way to sync the FluentValidation validation rules with client side rules.

An ordinary WebMatrix app in an Umbraco subfolder

Standard

I have an ordinary WebMatrix app with a bunch of .cshtml’s, a SQL CE database, some nuget dlls and helpers. And now after very little effort I seem to be able to run it beautifully together with an Umbraco 4.7 site. I still need to test it more thoroughly but initial tests have been running perfect.

Here’s how:

1) Add a reserved path for the app in web.config:

<add key="umbracoReservedPaths" value="~/umbraco,~/install/,~/myapplication/" />

2) Enable webpages in web.config:

<add key="webpages:Enabled" value="true" />

3) Add a separate web.config file in the app path (/myapplication) to set the cshtml base class to the standard WebPages page base type (System.Web.WebPages.WebPage), and not the Umbraco one (umbraco.MacroEngines.DynamicNodeContext):

<configuration>
  <system.web.webPages.razor>
    <pages pageBaseType="System.Web.WebPages.WebPage">      
      <namespaces>
        <add namespace="Microsoft.Web.Helpers" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>
</configuration>

Now I can run ordinary .cshtml files completely outside Umbraco context from my /myapplication/ folder.

Big thanks to Elijah Glover for helping me out with this.

I’m about to try the other way around aswell, i.e. run Umbraco from within a subfolder.

5 min: WebMatrix + jQuery UI + json + jQuery templates

Standard

Lets use WebMatrix to create a very basic db – > ui sample using jQuery goodness. We’ll get from 0 to a working sample in five minutes (more or less).

1. The WebMatrix site

First create a new site in WebMatrix using the Empty site template.

2. Database

Next define a Sql CE database file, call it db and add a table named product:

Also add some demo data in the table, so you have something to show later on.

3. Json

Now it’s time to create a file that will serve a list of records from the database using json. For that reason, go create products.cshtml with this simple code:

@{
    var db = Database.Open("db");
    var sql = @"SELECT * FROM product";
    var data = db.Query(sql);
    Json.Write(data, Response.Output);
}

So now we have data and some code to read it. So try it out by running products.cshtml. You should see a json representation of all your products in your browser window:

[{"id":1,"name":"a product"},{"id":2,"name":"another one"},{"id":3,"name":"a third"}]

4. The master template with references to js libraries

We are going to use some jQuery libraries in this sample. The jQuery base, jQuery UI for some nice looking UI and jQuery templates to render json data to html in a very conveniant template fashion.

All the libraries are available online, and there’s no need to use local copies at this point.

So, create a _layout.cshtml with the following content:

<!DOCTYPE html>

<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title></title>
        <link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/ui-lightness/jquery-ui.css" type="text/css" media="all" />
		<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script>
		<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js" type="text/javascript"></script>        
        <script src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.js" type="text/javascript"></script>

    </head>
    <body>
        @RenderBody()
    </body>
</html>

5. The main page

The last file in our WebMatrix project is the index.cshtml which only includes a jQuery UI styled button and a div placeholder for the result to begin with. On the click of that button we make a ajax call to get the data from our table, and render it to Html.

Here’s the complete code:

@{
    Layout="~/_Layout.cshtml";
}

<script>

    function renderResult(data)
    {
        // define the jQuery template with html code and
        // proper property names from the data query result       
        var markup = "<li>${id} : ${name}</li>";                                        
        $.template("listTemplate", markup);                    
        
        // render the template using the json data
        // iterates automatically over each each item in data        
        $.tmpl("listTemplate", data ).appendTo( "#result" );        
        
    }
	$(function() {
    
        // create good looking jQuery UI button element        
        $( ".button" ).button();
        
        // hook a getJSON to the click event of the button        
        $( "#getdata" ).click(function() { 
            $.getJSON('products.cshtml',renderResult);
        });
	});
</script>

<div id="getdata" class="button">Get data</div>
<ul id="result"></ul>

Here’s what your complete project in WebMatrix should look like, only three cshtml files and one database:

Result

Conclusion

Simple as that! Fun eh? And really useful I’d say.

Supporting non-js browsers when developing webapps sometimes feels like keeping support for Windows 3.11 when developing Windows apps. ;-)

WebMatrix MVC-ishness with Simple.Data and FormHelpers for CRUD

Standard

Building upon what I started with in my last post – a controller like cshtml page in WebMatrix – I have now added some functionality which means I have a basic, but working (demo state), generic CRUD workflow mimicing important parts of a regular Asp Net MVC 3 application.

The code here is in an experimental state but I have decided to write about it already because both I think it works out well and also I would very much appreciate any feedback I can get.

In this next step after my initial MVC-ish lab in WebMatrix I add data handling with the use of Mark Rendles geniously dynamic SimpleData data access library.

Addressing some of the problems I experience with Asp Net MVC 3 programming

Long story short – I am trying to use good parts from popular dynamic languages MVC frameworks in my .net Web programming. Parts where MVC 3 still is rather clumsy. I dont want to tire you with a theoretic discussion just now – instead I want you follow me through a code explanation. (Look for the short theory at the bottom of this post if you like.)

Here goes:

The controller

Here’s what I do in my controller /person.cshtml for the “edit” action:

// Define the SimpleData db connection and the table for the use 
// in this controller.
var DbFile = Server.MapPath("~/App_Data/StarterSite.sdf");
var Db = Simple.Data.Database.OpenFile(DbFile);
Page.SimpleDataTable = Db.Person;

// Act on the url-action ("edit" / "insert" / "display" / "edit")
switch (action)
{
    case "edit":

        // Find the record in the database and store in Page.Model
        Page.Model = Page.SimpleDataTable.FindById(id);

        if (!IsPost)
        {
            // Render the view
            @RenderPage(Page.ControllerUrl + "/_edit.cshtml");
        }
        else
        {
            // Update available properties in Page Model using 
            // Request.Form data

            DynamicForm.FormHelpers.UpdatePageModel();
    
            // Try to store data back to the database using 
            // SimpleData.Update

            // If update fails we return to the edit view with the 
            // error message from SimpleData.

            // The real user friendly validation should already be 
            // taken care of with jQuery validate,
            // this is the fallback safety validation.

            try
            {
                Page.SimpleDataTable.Update(Page.Model);
                Response.Redirect(Page.ControllerUrl);    
            }
            catch (Exception ex)
            {
                Page.Message = ex.Message;
                @RenderPage(Page.ControllerUrl + "/_edit.cshtml");
            }    
        }
        break;

The edit view

/person/_edit.cshtml is our edit view, and works just fine with just a minimal amount of code:

<body>
    <h2>Edit record</h2>   
    @if (Page.Message != "") { 
        <strong>@Page.Message</strong>
    }        
    @DynamicForm.EditorForModel()
    <a href="@Page.ControllerUrl">Back to list</a>
</body>

The helpers

I created a few helper methods in App_Code/DynamicForm.cshtml to make this possible:

@helper EditorForModel()
{...}
@helper InsertForModel()
{...}
@helper DisplayForModel()
{...}
@helper DeleteForModel()
{...}
@helper TableForModel()
{...}

The helpers make use of the data in Page.Model which is handled in the controller, either a single record (for Display, Edit and Delete) or a list of records (TableForModel). I also needed a way to add Label texts, and define the editors. For that I find a dictionary with necessary metadata much easier to work with than a conventional ViewModel with data attributes.

A ViewModelDefinition

To define exactly what I like to show in the view forms I make use of a ViewModelDefinition class with which I define data fields, label texts and CssClasses in the controller, like this:

var def = new DynamicForm.ModelDefinition();
def.AddColumn("id", "hidden");
def.AddColumn("name", "Name", "text", "mandatory");
def.AddColumn("comment", "Comment", "textarea", "mandatory");
def.AddColumn("submit","Submit","submit"); 
Page.ViewModelDefinition = def;    

The (preliminary) EditorForModel

In the EditorFormModel helper I use both Page.Model as well as Page.ViewModelDefinition to make the edit form.

@helper EditorForModel()
{
    
    var modelDict = (IDictionary<string, object>)Page.Model;
    
    <form method="post">
            @foreach (var columnDefinition in Page.ViewModelDefinition.Columns)
        {
                var col = columnDefinition.Value;

        string value = "";

        if (Page.Model == null)
        {
            if (col.DefaultValue != null)
            {
                value = col.DefaultValue.ToString();
            }
        }
        else
            if (col.DataField != null && col.DataField != "" && modelDict.Keys.Contains(col.DataField))
            {
                value = (modelDict[col.DataField] ?? "").ToString();
            }

        switch ((string)col.Type)
        {
            case "text":
            <div>
            <label for="@col.DataField">@col.LabelText</label>
            <input type="text" id="@col.DataField" name="@col.DataField" class="@col.CssClass" value="@value"/>        
            </div>
            break;

            case "textarea":
            <div>
            <label for="@col.DataField">@col.LabelText</label>
            <textarea id="@col.DataField" name="@col.DataField" class="@col.CssClass">@value</textarea>
            </div>
            break;

            case "hidden":
            <div>
            <input type="hidden" id="@col.DataField" name="@col.DataField" value="@value"/>        
            </div>
            break;

            case "submit":
            <div>
            <input type="submit" value="@col.LabelText"/>
            </div>
            break;
        }
    }
    </form>
}

Conclusion

I am still some steps from having code in such a quality where I can distribute this as a open source project, but I hope I will soon, or that someone else is doing it. It’s really no much work in total here as most is already in WebMatrix, and of course SimpleData.

As I said in the beginning of this post I would love to get any feedback on this.

Appendix

The MVC3-problem areas wanted to try to move away from

Data classes and Datacontext complexity. A genuine stable ORM & data layer is something one never should leave behind, but for many web applications I think SimpleData makes db-crud both good enough and as lightweight and “ceremony less” as it can be.

Handle localized (translated) texts. This is easier and more direct with a ViewModelDefinition dictionary than using DataAttributes on ViewModels.

Recompiling controllers. I have come to like the dynamic Rails/Django/Php approach to web development for the closeness and speed between editing code and seing the result. In short – without needing to recompile the full application (and resetting the sessions). By editing cshtml’s the individual files are the only ones that need recompilation and that is done in the blink of the eye.

Scaffolding views. The T4-scaffolding of views is nice and makes often 90% of the work. But the way I (and I guess many with me) work I redesign everything from data to html often in small iterations. And that for that to work good in MVC 3 I would need to edit T4 templates and regenerate views for each iteration. I like the MVC3 templating (EditorFor) better, but not as much as doing everything in a Razor helper where I have great control with the best syntax available imho.

Razor helpers reduce the use of “magic”. Make the helpers your own, change the code therein just like you want and make individual versions for different controllers – when you need.

I polish the helpers easily and the polish shines through to every part of the program where the global helpers are used. (If I need individual behaviour in a view that is easy to do just by copying the global helper and editing it in the particular view).

Tests

I do need testing in my WebMatrix projects. That is something I have to explore further. Any good ideas to share?

Follow up on the dynamicforms

I made a new approach to the dynamic forms in my HtmlFormHelper.