Posts about ASP.NET MVC

How to create a jQuery Mobile App using ASP.NET MVC

In this post I’ll show you how to create a mobile web app using jQuery Mobile and ASP.NET MVC 4.

I’ve used AppHarbor to host the app so you can see it action by clicking here.

Yummy Bakes

The source code for the demo in this post can be found on github.

The first step in creating a mobile ASP.NET MVC mobile web app is to either choose select the ‘Mobile Application’ project template or an empty project.

ASP.NET MVC project template

As personal preference I prefer the empty solution as it won’t be cluttered by controllers, views and scripts you don’t need.

In the layout file for the app (used as the template for other views) we add the CSS and JavaScript resources required.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>@ViewBag.Title</title>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css" />
    <link href="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/css")" rel="stylesheet" type="text/css" />    
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
    <script type="text/javascript" src="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js"></script>
    <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.7/jquery.validate.min.js"></script>
    <script type="text/javascript" src="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/js")"></script>    
</head>
<body>
    <section data-role="page" data-theme="d" id="@ViewBag.PageId">
        <section data-role="header"data-theme="e">
            <section id="header">
                <a href="@Url.Action("Index", "Recipe")">
                    <h2 class="header-text">
                        <img src="~/Content/Images/logo.png" alt="YummyCake">Yummy Bakes</h2>
                </a>
            </section>
        </section>
        <section data-role="content">
            @RenderBody()
        </section>
    </section>
</body>
</html>

Here we’re using the new ASP.NET MVC 4 bundling and minification functionality in combination with content delivery networks (CDN’s) to increase the performance of the application.

You can read more about bundling and minification in the post ‘ASP.NET MVC Mobile Performance Tip – Bundle and Minify‘.

jQuery Mobile data-* attributes

If you’ve not used jQuery Mobile before you may be wondering what the data-* attributes are for.

jQuery Mobile uses the attributes to apply styles and functionality to elements on the page.

As the same header will be used in all of the pages in this mobile web app we can define it in the layout file.

The call to RenderBody() is wrapped in a data-role= “content” attribute which jQuery Mobile uses to define the content of a page.

See the jQuery docs for more information about page structure.

Now we’ve created the layout template the next thing to do is create the ASP.NET MVC controller for the mobile web app.

using System;
using System.Linq;
using System.Web.Mvc;
using YummyBakesASPNETMVC.Data;
using YummyBakesASPNETMVC.Models;

namespace YummyBakesASPNETMVC.Controllers
{
    public class RecipeController : YummyBakesBaseController
    {
        public ActionResult Index()
        {
            return View(SampleRecipes.Recipes.Take(3).ToList());
        }

        public ActionResult Details(int id)
        {
            ViewBag.PageId = "recipe-details";
            return View(SampleRecipes.Recipes.Single(r => r.Id == id));
        }

        public ActionResult Find()
        {
            return View(SampleRecipes.Recipes);
        }

        public ActionResult AddReview(Review review)
        {
            review.DatePublished = DateTime.Now;                        
            //SampleRecipes.Recipes.Single(r => r.Id == review.RecipeId).Reviews.Add(review);
            return Content(RenderPartialViewToString("Review", review));
        }
    }
}

The Index action for the RecipeController will return a view model containing the top 3 baking recipes.

To keep things simple the recipes are coming back from a static list and not from a database.

In the view for the Index action the user will see text about the app, a link to a page to find recipes and a list of the top three recipes.

Yummy Bakes Home

The markup for the view is shown below.

@model IEnumerable<YummyBakesASPNETMVC.Models.Recipe>
@{
    ViewBag.Title = "Yummy Bakes";    
}
<p class="intro">
    From old favourites to new twists on modern classics, from sweet to savoury we've
    got a recipe just for you!</p>
<a href="@Url.Action("Find","Recipe")" data-role="button" data-icon="search" class="find-recipe-link">Find a recipe</a>
<ul data-role="listview" data-divider-theme="e" class="recipe-list">
    <li data-role="list-divider" class="list-divider">Top Recipes</li>
    @foreach (var recipe in @Model)
    {
        Html.RenderPartial("RecipeListItem", recipe);
    }
</ul>

Note how the RenderPartial method to output the list items.

Partial views are a great way of separating the responsibly of a view and help keep ASP.NET MVC mobile web apps in a maintainable structure.

Again if you’re new to jQuery Mobile the data-role=”listview” attribute in the ul tag is used to style lists, the data-role=”button” attribute makes a standard hyperlink look like a button for which we add an icon to by using the data-icon attribute.

The recipe detail view uses partial views to display information for the recipe for which CSS is used to add the background images and style the lists.

It also contains a form so users can submit reviews.

YummBakes Review

I’ve commented out the line in the code that would actually persist the review (because I don’t want to manage spam) so any reviews you add will only be shown locally on the page.

The JavaScript below shows the AJAX call used to submit a new review.

Pay attention to the line which refreshes the list view called in the complete event. Without this the list of reviews would not get updated. See the post ‘Don’t forget to call refresh when adding items to your jQuery Mobile list‘.

$(".review-form").validate({
    submitHandler: function (form) {            
        var data = {
            RecipeId: $('#recipeId').val(),
            Author: $('#name').val(),
            Title: $('#title').val(),
            Rating: $(".starRating span.chosen").length,
            Body: $('#review-body').val()
        };

        $.ajax({
            type: 'POST',
            url: $(".review-form").attr('action'),
            data: data,
            success: function (result) {
                $('.review-collapsible').trigger('collapse');
                $(".review-form")[0].reset();
                $('.reviews').append(result);
            },
            error: function (request, status, error) {
                console.log(request.responseText);
                console.log(status);
                console.log(error);
            },
            complete: function () {
                $('.reviews').listview('refresh');
            }

        });
    }
});

As we’ll see in this series about creating mobile web apps there are a number of ways of how we could have structured an application like this.

This example uses multiple pages, so whenever a user clicks on a link to see the detail for a recipe, a request is made to the server which is handled by a controller action with its’ own view.

In later posts in the series we’ll see how this differs to ASP.NET MVC single page applications.

ASP.NET MVC Mobile Performance Tip – Bundle and Minify

A few months ago I wrote a blog post about how you could improve the performance of your ASP.NET MVC apps using a third party library to compress and combine your CSS and JavaScript resources.

The latest release of ASP.NET (v4.5) comes with its’ own bundling and minification tools.

And the great news is they’re very easy to use.

For example if your layout file contained three CSS and four JavaScript resources

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/html5reset-1.6.1.css")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/photoswipe.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/respond.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/klass.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/code.photoswipe-2.1.6.min.js")" type="text/javascript"></script>
</head>
<body>
    @RenderBody()
</body>
</html>

You can bundle and minify CSS and Javascript resources for your ASP.NET mobile apps by using standard HTML like this

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title</title>
    <link href="/Content/css" rel="stylesheet" type="text/css" />
    <script src="/Scripts/js" type="text/javascript"></script>
</head>
<body>
    @RenderBody()
</body>
</html>

or like this using HTML helpers

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title</title>
    <link href="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Content/css")" rel="stylesheet" type="text/css" />
    <script src="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Scripts/js")"></script>
</head>
<body>
    @RenderBody()
</body>
</html>

Note: Scott Gu reckons the helper will probably be called Html.Bundle in the future.

Using HTML helpers gives you the advantage of adding a unqiue hash based upon the contents of the directory structure on the server for the script resource e.g.

Bundling and Minification Hash Files

ASP.NET will then cache the output for a year which means it will be served from the cache.

Should any files in a resource directory change the generated hash will also change and user will get an updated version of the file.

So how does ASP.NET MVC 4.5 bundling and minification perform?

This is Chrome resource graph for loading the page without any bundling or minification

Without bundling or minification

and here’s the resource graph for a ASP.NET MVC app using the new bundling or minification tools.

With bundling or minification

The images say it all!

ASP.NET MVC Mobile Performance Tip – Compress and Combine

In this post we’ll see how easy it is to optimise the performance of your mobile ASP.NET MVC site with the excellent SquishIt framework.

Excited you should be.

SquishIt can reduce the chatter between the browser and the server by combining your css or JavaScript scripts into single files.

This is important because there is a limit on the number of simultaneous connections that can be opened to a hostname (sub-domains count as different hostnames).

So the more scripts you have the longer it could take for a page to load.

See this page for more information http://ejohn.org/blog/browser-page-load-performance/

And that’s not all…

In addition to reducing the number of scripts SquishIt can also compress files using a minifier of your choice including the YUI compressor.

What’s even more impressive is even if you’re already using minified versions of your favourite JavaScript libraries, SquishIt can still improve the performance of your ASP.NET MVC site.

So how do you make ASP.NET MVC mobile site faster using SquishIt?

Here’s a razor layout file which uses three CSS and four JavaScript files.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/html5reset-1.6.1.css")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/photoswipe.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/respond.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/klass.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/code.photoswipe-2.1.6.min.js")" type="text/javascript"></script>
</head>
<body>
    @RenderBody()
</body>
</html>

Here’s the Chrome resource graph for loading the home page.

Without SquishIt

How to optimise your mobile ASP.NET MVC site

The first thing to is add the SquishIt NuGet package by Justin Etheredge to your solution. Alternatively you can download it from here.

Next create a new controller called Scripts and add two action methods called CSS and JavaScript.

In each action method use SquishIt to load and cache the resources. See the documentation for a detailed explanation.

public class ScriptsController : Controller
{
    public ActionResult CSS()
    {
        const string cacheKey = "css";
        Bundle.Css()
            .Add("~/Content/Site.css")
            .Add("~/Content/html5reset-1.6.1.css")
            .Add("~/Content/photoswipe.css")
            .WithCompressor(CssCompressors.YuiCompressor)
            .ForceRelease()
            .AsCached(cacheKey, "");

        var css = Bundle.Css().RenderCached(cacheKey);

        return Content(css, "text/css");
    }

    public ActionResult JavaScript()
    {
        const string cacheKey = "js";

        Bundle.JavaScript()
            .Add("~/Scripts/modernizr-1.7.min.js")
            .Add("~/Scripts/respond.min.js")
            .Add("~/Scripts/klass.min.js")
            .Add("~/Scripts/code.photoswipe-2.1.6.min.js")
            .ForceRelease()
            .WithMinifier(JavaScriptMinifiers.Yui)
            .AsCached(cacheKey, "");

        var js = Bundle.JavaScript().RenderCached(cacheKey);

        return Content(js, "text/javascript");
    }
}

Back in the razor layout change the code to load CSS and JavaScript files by calling the CSS and JavaScript action methods on the Scripts controller.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title</title>    
    <link rel="Stylesheet" href="@Url.Action("CSS", "Scripts")">
    <script type="text/javascript" src="@Url.Action("JavaScript", "Scripts")"></script>
</head>
<body>
    @RenderBody()
</body>
</html>

Here’s the Chrome resource graph the number and size of CSS and JavaScript files have been reduced.

With SquishIt

So with less data to transfer across the wire your site will perform a lot better on a mobile browser.