One file CRUD sample with NancyFx, SisoDb and HtmlFormHelper

Following my NancyFx & SisoDb experiments I’m adding some CRUD with the help of my HtmlFormHelper class. So, here’s a one file Nancy CRUD sample (well plus the .dll’s and HtmlFormHelper.cs).

Note : I’m still very new at NancyFx, and I’m doing this to learn myself, there’s better samples out there, showing how the gurus does stuff with Nancy. Have a look in the samples in the original Github repository. And theres also Nerd Beers by Tom Janssens. And Building a photoblog with Nancy by Kristof Claes

And be sure to read the Nancy official documentation

Demo

Code excerpts

The Poco, SisoDb will take care of it as is, no need to define a sql table or mapping:

public class Product
{
    public Guid SisoId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string SomeIgnoredProperty { get; set; }
}

The table template (using the Nancy built in Super simple view engine):

var tableTemplate = @"
    <table>
        <tr>
            <td>Name</td>
            <td>Description</td>
            <td colspan=""2"">&nbsp;</td>
        </tr>
        @Each.Products
            <tr>
                <td>@Current.Name</td>
                <td>@Current.Description</td>
                <td><a href=""/products/edit/@Current.SisoId"">Edit</a></td>
                <td><a href=""/products/delete/@Current.SisoId"">Delete</a></td>
            </tr>
        @EndEach
    </table>";

Defining the html form elements using HtmlFormHelper:

var productForm = new HtmlFormDescriptor("product-form");
productForm.Add("Name", required: true);
productForm.Add("Description");
productForm.Add("Submit", type:"submit");

Building the full page:

public string htmlPageView(string title, string htmlContent)
{
    var htmlPageTemplate = @"<html>
        <title>{title}</title>
        <body>
            {menu}
            <h1>{title}</h1>
            {content}
        </body>
        </html>";

    var htmlMenu = @"<ul class=""menu""><li><a href=""/products"">Products</a></li></ul>";

    var view = htmlPageTemplate
        .Replace("{title}", title)
        .Replace("{menu}", htmlMenu)
        .Replace("{content}", htmlContent);

    return view;
}

Nancy goodness in action:

Get["/"] = x =>
{
    string htmlInsertForm = "<h2>New product</h2>" + productForm.Html(action: "/products/insert");
    return htmlPageView("List products", htmlListProductNames() + htmlInsertForm);
};

Get["/edit/{id}"] = x =>
{
    Product product;
    string htmlEditForm = "";
    using (var uow = db.CreateUnitOfWork())
    {
        product = uow.GetById<Product>((System.Guid)x.id);
        htmlEditForm = productForm.Html(product);
    }
    return htmlPageView("Edit product", htmlEditForm);
};

Get["/delete/{id}"] = x =>
{
    string htmlDeleteResult = "";
    using (var uow = db.CreateUnitOfWork())
    {
        uow.DeleteById<Product>((System.Guid)x.id);
        uow.Commit();
        htmlDeleteResult += "<p>Successfully deleted the product</p>";
    }
    return htmlPageView("Delete product", htmlDeleteResult);
};

Post["/edit/{id}"] = x =>
{
    var htmlEditResult = "";
    Product product;
    using (var uow = db.CreateUnitOfWork())
    {
        product = uow.GetById<Product>((System.Guid)x.id);
    }

    // Update model and validate
    var validationResult = (HtmlFormDescriptor.ValidationResult)n.TryUpdateModel<Product>(Request.Form, ref product);

    if (validationResult.IsValid)
    {
        htmlEditResult = "<h1>Valid</h1>";
        using (var uow = db.CreateUnitOfWork())
        {
            uow.Update<Product>(product);
            uow.Commit();
            htmlEditResult += "<p>Updated product id " + product.SisoId.ToString() + "</p>";
        }
    }
    else
    {
        htmlEditResult = "<h1>Something is not valid</h1>";
        htmlEditResult += productForm.Html(product);
    }
    return htmlPageView("Edit product", htmlEditResult);
};

Full source

HtmlFormHelper Gist

Edit : Client side validation

I made some changes to be able to easier include the HtmlFormHelper client side validation script + add scripts and css’es in general:

public string htmlPageView(string title, string htmlContent)
{
string htmlPageTemplate = @"<html><head>
    <title>{title}</title>
    {css}
    {scripts}
</head>
<body>
    {menu}
    <h1>{title}</h1>
    {content}
</body>
</html>";

    string htmlMenu = @"<ul class=""menu""><li><a href=""/products"">Products</a></li></ul>";

    string htmlCss = @"<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>";

    string htmlScripts = @"<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>";

    var view = htmlPageTemplate
        .Replace("{title}", title)
        .Replace("{menu}", htmlMenu)
        .Replace("{css}", htmlCss)
        .Replace("{scripts}", htmlScripts)
        .Replace("{content}", htmlContent);

    return view;

}

Now all I have to do to create a form that has client side validation is:

var productForm = new HtmlFormDescriptor("product-form", includeClientSideScript: true);

The Nancy google group

The NancyFx google group is a great place to find q’s and a’s for how to use the framework. If you have a question – put it there – and you’ll likely get an answer by the Nancy gurus, Andreas Håkansson, Steven Robbins et al before you know it. They simply rock!

No fuzz adding properties

Oh, forgot to mention: to add another property, and storing it in the database is as easy as adding it to the Poco and the html form definition, just like I did with ArticleNumber here:

public class Product
{
    public Guid SisoId { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string ArticleNumber { get; set; }
    public string SomeIgnoredProperty { get; set; }
}

 

var productForm = new HtmlFormDescriptor("product-form");
productForm.Add("Name", required: true);
productForm.Add("Description");
productForm.Add("ArticleNumber", required: true);
productForm.Add("Submit", type:"submit");


There’s some “code first” for us (or rather code only), gotta love SisoDb!

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s