Efficient SEO In A Dynamic Context With Mustache Templating In .NET
maart 29, 2014
A step-by-step guide introducing two essential frameworks in order to create state of the art enterprise websites: mustache.js for client side and Mustache for server side usage.
Killing two birds with one stone
The overall concept of a given project here at Valtech is designed and thought through by designers, SEO experts and UX consultants. Consultants who are not limited by a developer mindset - thank god! Their ideas end up in staggering concepts, which often means that the design and concept of the entire solution is based on dynamic rendering of real-time information with the ability to be indexed by a search engine or accessibility tools.
In order to satisfy our needs for efficient search engine optimization (SEO) and to accomplish our basic task of creating state of the art enterprise websites that are easily maintained in a loosely coupled architecture, I would like to introduce a phenomenon in web development called Mustache templating.
By adopting this technology we will be able to kill two birds with one stone.
The SEO bird - It goes without saying that we want Google to index our sites properly (server side) without the crawler missing any important content, but this can get tricky at times when our solutions are based on the dynamic client side rendering of real-time information mentioned above.
The maintenance bird - A well-known problem of duplicate code arises more often than not when developers try to kill the first bird by letting the HTML markup exist in both the server side view (Razor etc.) and the client side script. Maintenance ends up being a massive pain.
The stone - To avoid both the SEO issue and the problem of duplicate code, I recommend using Mustache templating for client side and its server side counterpart - The Nustache engine for .NET.
Throughout the rest of this post I will show you how to do this by walking you through a simplified example - step by step. I will do this in the context of an ASP.NET MVC5 solution enhanced by Ninject and WebAPI2, thereby illustrating the newest and most ideal platform for building RESTful application interfaces on the .NET framework. Along the way I will make certain points clear using UML diagrams.
A categorized search To present a perfect example of the benefits of Mustache/Nustache templating, let’s start out by imagining the following scenario:
As a user I want to click a product category and view a list of products based on a selected category filter.
In order to make this a bit more tangible, the case for all examples are a state of the art clothing webshop that facilitates a categorization filter on products produced by the fictional brand “Brand’o”:
We can easily satisfy the user story by modifying our DOM directly through JavaScript or jQuery and thereby achieving dynamically rendered HTML based on object states:
[gist id="52718889d29b5843c95b"]
Well, it sort of does the job, but if we look at the big picture (enterprise projects, remember?) this does not accommodate any of our main objectives and will, at some point, become a pain to redo. Let’s walk through an example of why this implementation does not fulfil our key objectives: our SEO expert will be disappointed when he realizes that the initial search is rendered through client side scripting, because that means that the content is not crawled by Google. Then some might state: “That’s not realistic and I did of course create a server side renderer as well”, which in nine out of ten cases compromises the maintainability objective - simply because our HTML-markup will exist in both our view (razor etc.) and client side script.
Let's start our journey towards a maintainable webshop that facilitates a dynamic rendering of clothing as required by my creative colleagues. Let me take this a bit further and show you how I prefer to implement the key bits of our user story.
Building up a maintainable solution
ASP.NET MVC5 is the base for the upcoming examples in this post, so if you are not that familiar with the MVC pattern and its implementation in .NET, I suggest that you read this article provided by Microsoft first: Getting Started with ASP.NET MVC 5.
Without going into too much detail - I could really be talking about this all day - I will briefly explain that the solution in this example uses Ninject as the inversion of control container for dependency injection. Ninject uses the technique of dependency injection to break down applications into loosely coupled, highly cohesive components, and then glue them back together in a flexible manner - or as Ninject states: “Ninject makes your application more ninja-like!”.
First step is to create an implementation of my ISearchService
interface, which demands that all implementations contain ISearchResult Search(string category);
. Because this blog post is all about templating, I will create a simple DummySearchService
that returns an instance of ISearchResult
based on the category criteria. Ideally, this implementation would be some kind of integration to an external search provider like SiteSeeker or Google where another - maybe more advanced - implementation signature is required. In order to glue all this together Ninject is notified of all bindings through the DummySearchServiceModule
, whose responsibility is to describe injectable interfaces to implementations.
This might be a bit confusing at first, so I will let the UML-notation do its magic. In general, I love UML and agree with Martin Fowler in his statement “their (UML diagrams, red.) primary value is in communication and understanding. A good diagram can often help communicate ideas about a design, particularly when you want to avoid a lot of details.”
Our next step is to create a web service that enables the client side script to fetch data. This allows me to introduce ASP.NET WebAPI2, which is the newest release of its MVC inspired framework for RESTful application interfaces. I am not going to describe this in detail simply because there are numerous articles with thorough getting-started descriptions on how to install and configure your first RESTful API using ASP.NET WebAPI2. Please note that I am configuring my installation of the WebAPI to use the JSON serializer and camelCase datacontractresolver, provided by Newtonsoft, instead of the out of the box XML and PascalCase one.
As you might have already guessed, we proceed by creating an ApiController in order to handle incoming HTTP requests and return a JSON formatted instance of SearchResult
. It is of course necessary that our controller is able to receive an essential argument: string category
. ASP.NET WebAPI2 enables us to use the new RouteAttribute and RoutePrefixAttribute to create a matching url-pattern. To sum up, this is my new SearchApiController
- please note that it uses constructor injection in order to get the proper implementation of ISearchService
(ninja-style).
[gist id="73fb3ea3e50ff2232462"]
By creating an HTTP GET request with the proper header, I am now able to verify the application interface:
[gist id="148e589e42e7d28921e6"]
Products are obviously returned from our web service. These will function as data for our client side rendering of products in the list presentation illustrated earlier. But how do we actually consume and present this without compromising our maintainability requirements by introducing the annoyance of duplicate code?
It is time to properly introduce our saviour: Mustache/Nustache templating.
The concepts of {{mustache}}
Mustache - or {{mustache}} as it is often written to emphasize the curly braces that defines a tag in its syntax and from which it takes its name - is characterized by its “logic less” templating language in which you won’t find any If statements, Else clauses or For loops. Instead, Mustache uses tags. This may sound a bit confusing, but you can relax - it is not required that you master the Mustache language for you to use and benefit from the main points of this blog post.
Let me briefly explain how a template works and is structured in Mustache by elaborating our example a bit further while sticking to the clothing scenario:
[gist id="c7448c2daff3b7424b01"]
[gist id="481a4217342870d9c1e3"]
Our objects are parsed into the rendering engine along with the template, which - based on the properties of the objects - are converted from tags, like {{name}}, to values, like foo. The essential part is to understand how Mustache turns a combination of data and tags into readable html:
[gist id="8840a1ba1bd6f247013e"]
You might ask: Why Mustache and not some other jQuery templating framework? One of many great aspects of Mustache is the server side engine created for etc. Ruby, PHP and .NET. This engine is called Nustache and it allows us to accomplish dynamic rendering that is actually reusable in .NET - cool right?
Next, I would like to create a Mustache template that is reachable for both our server side and client side renderer. Simply a plain HTML-file, which contains the markup and tags matching the structure of our object. I name my file “product-result.mustache.html” and put it in the “~/Content/template/” folder.
UML is great for code inspiration when developing, because the diagram illustrates that the returned ISearchResult
consists of a collection of IMatch
. You probably guessed it already, but this means that our template should contain an iterator on the property Matches and of course tags for the Name and Url for every match.
[gist id="6e4996421aa7efffcef5"]
Dynamic client side presentation
Our client side counterpart of Nustache is called mustache.js and it allows us to parse out some readable HTML markup based on our previously illustrated HTTP response and the defined template. This is straightforward and only requires two steps: first up is to load the template and second step is to pass in the template that are stored in a variable, along with the object.
It is important to understand the essence of the following basic jQuery repository. $.search
is encapsulating AJAX and API logic and is therefore responsible for the interaction with our SearchApiController
:
[gist id="01c8e556a74db7892609"]
On the other hand, the implementation part is using - instantiating and interacting with - the repository and most importantly it creates readable markup through a separation of logic and presentation when onUpdate()is triggered.
[gist id="203783f1766759d27fbd"]
Please note that this implementation is absolutely basic and simplified in order to show the core principles of dynamic rendering with Mustache. The essential part to understand is that we initially load our template and pass this to mustache.js along with the result based on the user defined category – the returned result replaces the existing markup within the ul.results element. Also note that there are many other approaches to the implementation of mustache.js, just be aware that my repository-like approach creates three critical components in order to separate the responsibilities properly.
In order to use this code we need to add a ProductController
and a Search-action with a corresponding view, which contains a reference to a bundle consisting of respectively our repository and the equivalent implementation. My bundle is created using the Microsoft.AspNet.Web.Optimization approach, but similar frameworks like Casette.AspNet are useable as well:
[gist id="67679d11841a9e546014"]
This approach solves our overall user story: “As a user I want to be able to click a product-category and see a list of products based on my selected category filter.”… but not our main criteria, which causes the face colour of our SEO expert to turn slightly red. To change it back, we can implement a Nustache server side renderer that underlines our SEO and maintainability objective.
Server side rendering of our shared template
What we need to replicate server side is the previous onUpdate code that was responsible for initiating the template rendering by using the to_html
method in mustache.js:
[gist id="27c68cc53fc3918f2451"]
The big difference is that it should happen before Razor hands over the responsibility, which means it is time for some server side magic.
Nustache is available as a nuget package, and through the “Package Manager Console”, the “Nustache –version 1.13.8.22” package can quite easily be installed. As previously mentioned, this enables us, just like we did with mustache.js, to render out readable markup by combining a template with an object.
Like the ApiController
, the controller uses Ninject to catch the instance of our ISearchService
. As you might remember, the ISearchService
implementation contains a Search(string category)
method, which is used to facilitate an initial search based on the default category “pants”, that returns an ISearchResult
.
Nustache.Core.Render.FileToString
is somewhat the equivalent to Mustache.to_html
and is requested with respectively a physical template path, which can be resolved through HostingEnvironment.MapPath
, and an instance of ISearchResult
- it is crucial to understand how we once again are using our shared template in order to create readable HTML.
Next step is to create a simple model to pass along to the view, which contains the rendered markup as MvcHtmlString
and should be initiated and set right after the Nustache.Core.Render.FileToString
finishes up.
[gist id="3693adf2a7ac47be45d0"]
It is of course required that we make our previously created view strongly typed by simply adding a @model ProductViewModel
statement and replace the <!-- dynamic content -->
comment with the dynamically rendered markup like this:
[gist id="f1996b2466e04b718421"]
Our journey has come to an end and we’ve now finished up developing. The last part – and maybe the most important – is to test that our approach really works as intended. By firing up the solution and navigating to the previously created ProductController’s Search-action we are able to verify that we now have the ability to see a list of products within the default category “Pants”. As you might remember, we actually had the exact same feeling when we did the first jQuery - the only implementation that were not aligned with our key objectives... so the question is...
...did we at this point take down both birds and thereby meet the objectives concerning search engine friendliness and maintainability?
Let's find out
By quickly looking into the non-modified source of our new webpage, it unveils that our products have been rendered server side and is therefore visible to e.g. the Google crawler – great!
It is also clear that the maintainability objective has been fulfilled, since we are using the same template for server side and client side rendering, which eliminates duplicate code and therefore increases reusability.
Our solution was build using a solid MVC5 foundation that consisted of interchangeable components glued together in a flexible manner by Ninject (ninja-style). The Search component was reused by the application interface, which was constructed using ASP.NET WebAPI2, and the ordinary Controller handling incoming HTTP requests.
In order to implement a shared templating concept, I introduced two essential frameworks, mustache.js for client side and Nustache for server side usage, that are both built on top of the Mustache template language. These were the centrepiece in a flexible and maintainable implementation covering both client side and server side usage.
The demands of state-of-the-art websites requires action in order to maintain a solution that in the long run will be enjoyable and easy to develop. This is a suggested approach and is evolving over time in our enterprise solutions, so please keep in mind that everything is kept at a simplified level for the sake of this blog post.
I urge you to leave a comment or get in touch if you have any questions or feedback regarding any of this. Thanks!