[Update 8/15/2012] Update sample to Web API RTM packages

As Web API is released with ASP.NET MVC 4 beta, it can be used in both web host and self host. You can view a sample code for self host here.

When writing self host app, you may probably want to use template engine to show web pages just like in Sinatra or Nancy. However, Web API doesn’t natively support it right now. You can use MVC but it depends on ASP.NET which can’t be self hosted.

This article is a tutorial on how to use latest Razor Engine v3 within Web API self host app.

Setup Web API Self Host Project

Follow the tutorial at here.

Install Razor Engine v3 Nuget Package

image

 

Add one more route to serve web page request

config.Routes.MapHttpRoute(
    "API Default", "api/{controller}/{id}",
    new { id = RouteParameter.Optional });

config.Routes.MapHttpRoute(
    "Default", "{controller}/{action}",
    new { controller = "Home", action = "Index" }); 

Inline Template

Add HomeController.cs to the project

using System.Net.Http;
using System.Web.Http;
using RazorEngine;

namespace SelfHost
{
    public class HomeController : ApiController
    {
        public HttpContent Index()
        {
            string template = "Hello @Model.Name! Welcome to Web API and Razor!";
            string result = Razor.Parse(template, new { Name = "World" });

            return new StringContent(result, System.Text.Encoding.UTF8, "text/html");
        }
    }
}

Web API doesn’t has a html media formatter right now, so I have to use HttpContent as return type to prevent it from using default JSON or XML formatter to format the return content.

Open browser and visit http://localhost:8080/, it should show the content:

image

 

Rendering Template files (cshtml)

Razor engine supports to inject resolver to resolve template name to template content. I will resolve template name to embedded resource content in this tutorial. You can resolve it from physical file like what MVC did as well.

Put following coding just next to the routing code

string viewPathTemplate = "SelfHost.Views.{0}";
TemplateServiceConfiguration templateConfig = new TemplateServiceConfiguration();
templateConfig.Resolver = new DelegateTemplateResolver(name =>
{
    string resourcePath = string.Format(viewPathTemplate, name);
    var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourcePath);
    using (StreamReader reader = new StreamReader(stream))
    {
        return reader.ReadToEnd();
    }
});
Razor.SetTemplateService(new TemplateService(templateConfig));
Next change the HomeController to use template file name to render
using System.Net.Http;
using System.Web.Http;
using RazorEngine;
using RazorEngine.Templating;

namespace SelfHost
{
    public class HomeController : ApiController
    {
        public HttpContent Index()
        {
            var model = new { Name = "World", Email = "someone@somewhere.com" };
            string result = Razor.Resolve("Index.cshtml", model).Run(new ExecuteContext());
            return new StringContent(result, System.Text.Encoding.UTF8, "text/html");
        }
    }
}
 
Add template file Index.cshtml to Views folder and set it as embedded resource
image

Copy the following content to the Index.cshtml file (Note: there is a known bug in Razor editor, which will hang when copying and pasting. Please open it by Html editor instead)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
    <head>
        <title>Hello @Model.Name</title>
    </head>
    <body>
        Email: <input type='text' value='@Model.Email'></input>
    </body>
</html>

 

Run the application and it will show the content in browser.

image

 

Support Layout page

Since we already implemented the resolver, Razor will use it to resolve the Layout template as well. So the change will be very simple.

Add Layout.cshtml file to the Views folder and set it as embedded resource.

Copy the following content to the file:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
    <head>
        <title>Hello @ViewBag.Title</title>
    </head>
    <body>
        @RenderBody()
    </body>
</html>

Replace Index.cshtml with following content:

@{
    _Layout = "Layout";
    ViewBag.Title = @Model.Name;
}
Email: <input type='text' value='@Model.Email'></input>

 

Download Sample Code

 

Hongye Sun