Fork me on GitHub

ServiceStack's new HTML powers - the website framework

Razor Rockstars is a ServiceStack demo website showcasing ServiceStack's new MVC Razor Engine support and its enriched HTML story with multiple view engine support and No Controller / No Ceremony development options. In many cases we've gone beyond what MVC provides with many new and natural features optimized for developer happiness, fast iteration times and run-time performance, putting the fun back into .NET / Mono web development!

Install via NuGet

ServiceStack's Razor ViewEngine is an optional .NET 4.0 add-on that's self-contained within the RazorFormat plugin which can be easily added to any empty ASP.NET or Console Application project via NuGet with:

PM> Install-Package ServiceStack.Razor

Once added to your project, opt-in to enable the Razor feature in your AppHost with:


    Plugins.Add(new RazorFormat());
    
Source code embedded in all pages

All pages includes the code and markup used to render itself

To make it easier to explore all features on this site and to provide a better idea of how it all fits together, all pages include gists of the source code used to render itself. Source code for this entire website is in the RazorRockstars Github project.

Website framework features

We've added features beyond MVC in true ServiceStack-style: by enhancing your existing services, working as you'd expect it to in a REST service framework:

Runs Everywhere

Like the rest of ServiceStack, you can create websites and REST services in any host on any platform, e.g:

Live ASP.NET and Self-Hosting demos

Live Demos are Developed on VS.NET and Deployed to Linux

All servicestack.net demos are developed on Windows with VS.NET and are git-deployed to the same Ubuntu vServer with Nginx / MonoFastCGI.

Both the ASP.NET Razor Rockstars and the Self-Hosted replica are identical except the SelfHost AppHost inherits from AppHostHttpListenerBase and all its assets have the build action set to Copy if Newer so they're copied to the /bin directory after each build making it suitable for xcopyable deployment.

Windows Service

As we expect it to be a popular use-case we've added a version of Razor Rockstars running inside a Windows Service complete with install.bat / uninstall.bat Windows Service util scripts.

Nothing to learn

Invisible API - just you and your IOC

One of ServiceStack's core objectives is to retain an invisible API that gets out of your way. The ServiceStack service itself is a classic example, it's just a simple C# class auto-wired with your registered dependencies that accepts any user-defined Request DTO and lets you return any object which is automatically serialized into the expected Response Content-Type. Composable and re-usable functionality can be applied to all your services via Request / Response Filters, Filter Attributes, Validators or by extending a common base class - all of which get auto-wired with your registered dependencies. Even Razor views have access to your IOC dependencies.

You retain complete control over the Request DTO, Implementation and Response - added features simply enhance your existing models and services. We refer to this style as starting from ideal C#, and project-out and is one of the key approaches we use to promote a frictionless dev workflow, i.e. instead of having your C# code bind to a foreign API abstraction, ServiceStack builds functionality around your untainted C# classes and DTOs (unhindered by artificial APIs). This makes your logic more re-usable and is how any new feature we add to the framework is immediately able to work with your existing services without any code-changes required. E.g. you can code as you would normally and throw C# Exceptions and the ideal HTTP Response gets emitted, you also have access to rich fluent validation that supports returning typed structured error responses back to C# clients.

Include Partials from other view engines

Unlike many web frameworks, ServiceStack lets you include Partial views from other registered view engines. This is ideal for Content heavy pages where you can use MVC Razor format for a precise layout whilst maintaining the content of your dynamic pages in Markdown.

All Dead and Alive individual Rockstar pages are maintained in this way.

A Complete Web + REST Services Stack

The new Razor and multiple HTML ViewEngine support now transforms ServiceStack from a Web Services framework to a complete Website + REST/SOAP/MQ services stack which provides a clean replacement for MVC, WCF or WebApi.

This is a clean-break from the layers of legacy frameworks that have been added to ASP.NET over the years. We've made everything simpler by removing all existing ASP.NET layers and xml-encumered providers added on top of IHttpHandler's since .NET 2.0 and replaced them with clean, testable code-first providers based on urls and clean POCOs - all working seamlessly together.

HTML format supports multiple pluggable view engines

HTML support works just as you would expect it to exist on a REST service framework - you get to re-use your existing web service implementation where HTML is just another Content-Type:

ServiceStack Architecture

ServiceStack supports multiple view engines out-of-the-box: By default HtmlReport and Markdown Razor is pre-registered, whilst Razor support can be installed via NuGet.

When the client requests HTML Content-Type, ServiceStack will cycle through all registered view engines to find a matching view, if no matches are found the HtmlReport is used as a fallback which provides a readable and semantic HTML layout letting you visualize all the data returned from your web service at a glance.

One simple and unified HTTP stack

ServiceStack has a single, simple unified HTTP stack. There is no duplicate or supplementary functionality that only works for HTML vs Services. Everything is kept simple: There is 1 set of Routes, 1 way to create a Service, 1 set of Request / Response filters, 1 Validation model. All of ServiceStack's plugins and providers work equally well across all services and can even be shared from within MVC / WebForms hybrid solutions.

Add HTML views to existing services

The benefits of this are prominent, you only have a single implementation for all your Mobile, Desktop or Web Browser clients. By default, your clean C#-only services is accessible via HTML, JSON, XML, CSV, JSON, SOAP, ProtoBuf and MQ endpoints - all with no effort.

Solution view of Rockstars page

A live example of this is the RockstarsService.cs which is available by any of the defined custom routes, e.g:

/rockstars
html json xml csv jsv
/rockstars/1
html json xml csv jsv
/rockstars/aged/27
html json xml csv jsv

When viewed in a browser it will return the HTML output generated by the Rockstars.cshtml view embedded inside the specified HtmlReport.cshtml template using the model populated by the RockstarsService.cs

Unlike MVC (which has a convention for views based on the name of the controller), ServiceStack's view selection is based on the name of the Response or Request model (DTO) returned. E.g. If your Service returns a RockstarsResponse then we first look for a view of the same name as the Request DTO called Rockstars.cshtml followed by the Response DTO name RockstarsResponse.cshtml (in all registered view engine extensions).

As ServiceStack requires Request DTO's to be unique, you are free to layout the views in any logical file system structure you wish under the /Views folder and are not forced into any existing MVC /Views/ControllerName/ViewName convention.

Change Views and Layout templates at runtime

The above convention is overrideable where you can change both what View and Layout Template is used at runtime by returning your Response inside a decorated HttpResult:


    return new HttpResult(dto) {
        View = {viewName},
        Template = {layoutName},
    };
    

This is useful whenever you want to display the same page in specialized Mobile and Print Preview website templates. You can also let the client change what View and Template gets used by attrubuting your service with the [ClientCanSwapTemplates] Filter:


    [ClientCanSwapTemplates]
    public class RockstarsService : RestServiceBase { ... }
    

This attribute allows the client to change what View gets used with the View and Template QueryString or FormData Request Params. A live example of this feature is used to change the /rockstars page:

The No Ceremony option - Dynamic pages without Controllers

Many times (especially for read-only pages) Controllers add un-necessary overhead and just calling your dynamic Razor (or Markdown) pages directly will promote more cohesive pages requiring less code. Especially if you're already encapsulating your data access logic behind domain services and repositories - the overhead of a controller and action methods just adds un-necessary noise, that ends up being harder to test than pure C# code.

Pretty urls by default (no custom Routes needed)

ServiceStack has great support for this story where it lets you omit the .cshtml or .md page extensions and it still executes the desired page but with a pretty url. When calling dynamic pages with .ext (as done by VS.NET when hitting F5 inside a page) it is automatically re-directed to the pretty url version (saving a YSOD you might be used to with MVC):

Default pages for directories

The Above url shows the behaviour when requesting the default document default.cshtml which gets redirected to the alias url of its parent directory.

Single vs Multiple directories

The Dave Grohl and Eddie Vedder content pages show different ways of structuing the same page components whilst retaining the same url. The Dave Grohl example shows how you can keep all Rockstar pages in a single directory with different names for each Grohl.cshtml razor page and GrohlContent.md partial markdown view.

Eddie Vedder (and all the other Rockstars) use multiple sub directories to maintain their dynamic content pages and the different components that make up each page. Regardless of which layout you go with, you can still access the each page with the same case-insensitive pretty url:

Keep all views and their assets together

Despite both options yielding the same result, whenever you have many similar content pages it becomes a good idea to adopt the 'multiple sub-directory' convention which apart from giving each page more symmetry, it will allow you to group all the websites dynamic and static content, images and css within the same folder that makes copying, updating and deploying as easy as dragging and dropping a folder.

Cascading Layout Templates

Cascading Layout templates

Cascading layout templates is our simpler solution for MVC Areas, basically if you don't specify a Layout in the Razor page, the _Layout.cshtml that's nearest to the directory where the page is located gets used.

E.g. if there is a _Layout.cshtml in the current directory it will use that first, fallbacking to its parent directory all the way up until it reaches the Root web directory. Finally if there are no _Layout.cshtml templates to be found the default /Views/Shared/_Layout.cshtml will get used. Cascading layout templates is what allows 'dead' and 'alive' Rockstars to share different website templates:

Rockstars that have passed

Rockstars still Rocking it

Smart View Pages

One features Controllers have is the ability to inspect the incoming request. Inside Services, ServiceStack takes care of Request Binding and automatically populates your Request DTO based upon the HTTP Request Params. When calling pages directly (i.e. without Controllers) there are still a few ways to access the incoming HTTP Request data:

Pages with typed View Models

In the same way ServiceStack populates the Request DTO in Services, it will auto populate your View model by in Views when inheriting from the Generic ViewPage<> as base class as seen in /TypedModelNoController:


    @inherits ViewPage<Rockstars>
    

This will result in the typed @Model being populated from the HTTP Request params

Pages with dynamic View Models

The above solution requires an existing typed Request DTO / Input Model. There's also the option of not requiring a View Model when inheriting from the non-Generic ViewPage as seen in /NoModelNoController:


    @inherits ViewPage
    

In this case @Model is a DynamicObject where each dynamic access is delegated to IHttpRequest.GetParams() which looks for each param in the Request's QueryString, FormData, Cookies and Items.

Access Request / Response properties in Views

In addition to the @Model property, each View also has access to base.Request / base.Response properties for more fine-grained access to ServiceStack's IHttpRequest and IHttpResponse types.

Access IOC dependencies directly in Views

For dynamic views to also fullfill the roles of Controllers they need to be smart, which is why we've enabled views the ability to resolve your registered IOC dependencies with:


    var provider = Get<IYourProvider>();
    

In addition to accessing IOC debendencies, base classes also provide quick access to the most common providers like ADO.NET's IDbConnection as well as ServiceStack's clean Session and Caching providers.

Many Micro ORMs like ( OrmLite and Dapper) provide extension methods on ADO.NET's IDbConnection making it trivial to perform common db tasks. Here's an example of filtering the results of the Rockstar table with a typed Request Param:


    var rockstars = Db.Select<Rockstar>(q => q.Age == Model.Age);
    

Easily configure custom error pages in code

Since all common web tasks should be easy to configure, we've made it easy to register your own custom IHttpHandler's for different HTTP Status codes which you can do in your AppHost with:


    SetConfig(new EndpointHostConfig {
        CustomHttpHandlers = {
            { HttpStatusCode.NotFound, new RazorHandler("/notfound") }
        }
    });
    

Which you can test by looking for a Rockstar that doesn't exist on this site, e.g:

This rule tells ServiceStack to execute the /notfound Razor page for all 404 requests. The page referenced by Razor handler can be any dynamic razor page (i.e. not just a static html page) - which is extremely useful for Single Page Apps taking advantage of the DOM's history.pushState().

Markdown built-in

Another templating language we're especially fond of is Markdown. Although as the name suggests it's more of a Mark Down language since it's able to express commonly used HTML elements used for structuring content down into a simple syntax you may conventionally see published in ascii-only environments like plain-text email.

Maintain Content in Markdown (ideal for Content)

Markdown's overriding design goal is to be as human readable as possible where markdown text published on its own is still readable as-is and can be easily written in any text editor, without the need for any Visual HTML designer. These properties make Markdown the choice language to capture and maintain user content as done in many popular sites including StackOverflow and GitHub.

Include Partial Markdown views in Razor pages

We loved Markdown and Razor so much that included in ServiceStack is an enhanced version of Markdown with Razor functionality and Syntax called Markdown Razor which should be instantly familiar to existing Razor users.

As we expect Razor + Markdown to be an increasingly popular combination we've extend @Html.Partial() support to also embed Partials from different View Engines. This feature lets you embed any Markdown Page as we've done in each of the content-heavy Rockstar pages using the standard Razor Partial syntax:


    @Html.Partial("Content")
    

Which tells ServiceStack to embed a Partial named Content inside the page at that location. First it will look for a Partial named Content.cshtml followed by a Partial named Content.md if it reaches the Markdown Razor View Engine. Initially it searches the current directory, followed by any matching Partials in the /Views/Shared folder.

Build entire website pages using just Markdown Razor + static _Layout.shtml templates

Despite it's simple roots, Markdown Razor is a featured View Engine capable of rendering complete websites as done with the content-heavy (ajax/pushState enhanced) servicestack.net/docs/ website - written entirely and maintained using Markdown Razor.

Provide access to 'Markdown only' content

Having such deep control over the implementation of each View engine allows us to do interesting things like being able embed partials from different view engines and allowing you to fetch the text-only Markdown version of each page by changing the format returned using the ?format=text.bare query string.

Optimized for developer productivity

One of the areas where dynamic languages are holding over .NET is with fast iteration times enabling quick dev cycles. Whilst compilation times increase with every new page and class added to an ASP .NET Web project, many popular dynamic languages are experimenting with Live Reloading letting them quickly see changes in their browser after hitting Ctrl+S. Iteration times are one of the areas in most need of TLC in .NET and it's something we aim to optimize as much as possible without sacrificing run-time performance by maintaining 2 modes: 'Debug' (Development) optimized for start times and a 'Release' (Deployment) mode optimized for runtime performance. This mode is automatically inferred by ServiceStack on Start-up but is overridable with:


    SetConfig(new EndpointHostConfig {
        DebugMode = true,
    });
    

Great performance, Optimized for run-time and iteration times

MVC Razor is an extremely capable view engine with an elegant syntax, unfortunately it's quite slow to compile where by comparison this basic Razor Page is 39x times slower to compile whilst being 1.76x times faster to run than the functionaly equivalent Markdown Razor page. We're huge fans of the rich functionality provided by MVC Razor Format and we also agree performance is one of the most important features but iteration-times also matters as it has a direct impact on developer productivity and we believe should be given more prominance over micro-optimizations with large start-up costs as any perf benefits gained can be marginalized behind a good caching strategy. We continue to develop with this balance in mind and are continually looking to improve start-up times where possible (in DebugMode).

Automatic reload of modified views, layout templates and partials (in Debug mode)

The best way to avoid the Start-Up penalty is to avoid having to restart the AppDomain in the first place. So in Debug Mode we'll also do this where a background file system watcher monitors all pages, partials and Layout templates for modifications and recompiles and auto-reloads them on the fly, all-ready to deliever instant response time once the page is requested.

Future developer productivity enhancements

We prefer not to have to deal with these work arounds, but as Razor the de-facto view engine in VS.NET (with its built-in intelli-sense), it has become the most familiar templating language understood by .NET developers today, so it pays to make the extra effort as we see it will likely remain the most popular view engine developers use. One area we'll be exploring is maintaining binary caches of Razor templates which would survive beyond AppDomain restarts (if that's at all possible).

Another way to improve start times is to create a new HTML-only version (based on Markdown Razor's core) and replicate much of MVC Razor's functionality. A new implementation in this way stands to be even faster than Markdown Razor since it avoids the Markup-to-HTML penalty. More importantly being in control of our own implementation allows us to be more innovative and lets us borrow pages from other languages play books.
i.e. it could be nicer if Razor syntax was more declarative and less mechanical where instead of @RenderBody() you could just have [body] and still retain the same syntax to include any [section], [partial] or [var] etc. This would be friendlier and easier for content editors to grok as they don't need to remember the implementation mechanics and can just declare their intent. Here are some more potential examples:

    
    [body]
    [twitter-feed for:ServiceStack size:10]
    [sidebar with:links,ads]

    [foreach link in links]
        <a href="[link url]">[link name]</a>
    [/foreach]
    

Optimizing for Single Page Apps

One way we're currently improving the situation (that also provides a better UX for end-users) has been focusing on making ServiceStack the ideal platform for Single Page Apps - to this end, we're already shipping many best-of-class features and since Single Page Apps rely on client-side views for rendering, they escape the .NET compilation tax.

With the latest release of WebStorm, JetBrains gives us a glimpse into the development experience of Live Editing where they showcase the instant feedback loop possible when developing a rich client-side AngularJS App With WebStorm and Chrome.

Up until this point we've been recommending using a MVC + ServiceStack hybrid template for Single Page Apps. With this release of MVC Razor support, ServiceStack is now a complete and we're able to simplify the stack by removing the dependency on MVC and will begin shipping new Single Page App templates for the most popular client-side frameworks, with: AngularJS and Backbone.js planned for initially. We'll continue to improve this story and ensure first-class support for advanced Web App features like history.pushState(), which has always been a bit awkward to do in MVC.

Hybrid Dynamic Web + Typed Services Stack - Best of both worlds

Another option we're considering is to provide a hybrid Web + Web Services approach with tight-integration between ServiceStack and one of the dynamic languages with a focus on fast iteration times and Live Reloading enabled. We still believe in typed an end-to-end framework remains the best long-term solution for web services. But with the ASP.NET packaging model the way it is and the slow compilation times of .NET, it's becoming increasingly hard to ignore the productivity benefits being had in other dynamic languages.

So far Google's new language for the web Dart is looking like a stand-out here that should appeal to C# devs thanks to its familiar syntax (we like it because it supports the same platforms ServiceStack does :). Dart already holds a number of advantages over JavaScript and the Dart team and Chrome engineers have been working closely together to improve the integration between Dart IDE and Chrome where they're actively releasing new custom builds of Chrome that allow debugging of native Dart from inside both Dartium and the Dart IDE. We're going to explore this story further and if it looks to provide productivity benefits we'll produce a fast native comms pipeline between ServiceStack and the Dart VM runtime. We have already developed great HTTP integration with ServiceStack with one of the most fluent, intuitive API's you're likely to see in a Json Client.

Implementation

AppHost /AppHost.cs

In every ServiceStack web service there is a single AppHost which contains all your services configuration and registration (in code). The source for the Razor Rockstars AppHost is below, it performs the following things in this order:

  1. Tells ServiceStack which Assemblies to scan for registering existing services
  2. Register the MVC Razor Plugin (requires .NET 4.0)
  3. Register which DB to use - Razor Rockstars uses OrmLite + Sqlite (32bit/Mono compat)
  4. Create the Rockstar table if it doesn't already exist and insert all Seed Data
  5. Override ServiceStack's 404 Handler with the /NotFound.cshtml Razor page
ServiceStack/3.954 Unix/Mono