Skip to content
A RESTful library for ASP.NET MVC
C# Other
Find file
New pull request
Latest commit d0e2051 @bbyars Converted readme to markdown
Failed to load latest commit information.
.nuget Modified NuGet.targets to allow automatic download of nuget.exe if it…
RestMvc.Example.Mvc4 Updated all projects to target .NET 4.5 and ASP.NET MVC 4. Used NuGet…
RestMvc.Example Updated all projects to target .NET 4.5 and ASP.NET MVC 4. Used NuGet…
RestMvc.FunctionalTests Removed usages of deprecated Text.StartsWith() and replaced with Is.S…
RestMvc.UnitTests Removed usages of deprecated Text.StartsWith() and replaced with Is.S…
RestMvc Updated all projects to target .NET 4.5 and ASP.NET MVC 4. Used NuGet…
packages Adding packages/repositories.config
.gitattributes Normalizing line endings
.gitignore Converted readme to markdown
CONTRIBUTORS Updated all projects to target .NET 4.5 and ASP.NET MVC 4. Used NuGet…
LICENSE Normalizing line endings Converted readme to markdown
RestMvc.Example.nuspec Updating build script to regain old CM.NET stuff
RestMvc.FunctionalTests.nuspec Updating build script to regain old CM.NET stuff
RestMvc.nuspec Updating build script to regain old CM.NET stuff
RestMvc.sln Updated all projects to target .NET 4.5 and ASP.NET MVC 4. Used NuGet…
RestMvc.sln.DotSettings Removing unwanted stuff from Dependencies folder
TODO Normalizing line endings

What is RestMVC

RestMvc is a simple library for building RESTful services in ASP.NET MVC. It's primary purpose is to provide routing and content negotiation (conneg). The routing differs from other RESTful routing libraries, like SimplyRestful, in that the route is defined alongside the action that receives the route. It was largely inspired by the Ruby framework Sinatra (


public class OrdersController : Controller
    public ActionResult Index() { ... }

    public ActionResult Create() { ... }

    [Get("/orders/{id}.format", "/orders/{id}")]
    public ActionResult Show(string id) { ... }

    public ActionResult Edit(string id) { ... }

    public ActionResult Destroy(string id) { ... }

// In Global.asax.cs
// or RouteTable.Routes.MapAssembly(Assembly.GetExecutingAssembly());

The code above will do the following:

  • Create the routes defined by the HTTP methods and URI templates in the attributes. Even though System.Web.Routing does not allow you to prefix URI templates with either / or ~/, I find allowing those prefixes can enhance readability, and thus they are allowed.
  • Route HEAD and OPTIONS methods for the two URI templates ("orders" and "orders/{id}") to a method capable of handling those methods intelligently.
  • Route PUT and DELETE for /orders, and POST for /orders/{id}, to a method that knows to return a 405 HTTP status code (Method Not Supported) with an appropriate Allow header. This method and the ones that handle HEAD and OPTIONS are defined as virtual on RestfulController. If you want them mapped by RestMvc, but want to customize them (e.g., adding a body on OPTIONS), you can subclass RestfulController and override the appropriate methods.
  • Add routes for tunnelling PUT and DELETE through POST for HTML browser support. Creating a form with a hidden field called _method set to either PUT or DELETE will route to either Edit or Destroy.
  • Notice the optional format parameter on the GET method actions (Show uses it; Index does not). Routes with an extension are routed such that the extension gets passed as the format parameter, if the resource supports multiple representations (e.g. /orders/1.xml routes to Show with a format of xml). The ordering of the URI templates in the Get attribute is important. Had I reversed the order, /orders/1.xml would have matched with an id of "1.xml" and an empty format

The last point is a convenient way to handle multiple formats for a resource. Since it's in the URL, it can be bookmarked and emailed, with the same representation regardless of the HTTP headers. Even if content negotiation is used, it allows you to bypass the standard negotiation process. RestMvc does not automatically provide these routes for you - notice that two URIs are specified on the Show method.

Content negotiation is provided as a decorator to the standard RouteHandler. One of the problems I've seen with some other RESTful routing libraries is that they define the IRouteHandler internally, which removes your ability to add any custom hooks into the routing process. My hope is that providing the functionality as a decorator allows for more flexibility.

// In Global.asax.cs
var map = new MediaTypeFormatMap();
map.Add(MediaType.Html, "html");
map.Add(MediaType.Xhtml, "html");
map.Add(MediaType.Xml, xml");

var connegRouter = new ContentNegotiationRouteProxy(new MvcRouteHandler(), map);

// or RouteTable.Routes.MapAssembly(Assembly.GetExecutingAssembly(), connedRouter);

In the absence of a route URI template specifying the format explicitly, the connegDecorator will examine the Accept request header and pick the first media type supported in the map. Wildcard mathes are supported (e.g. text/* matches text/html).

The content negotiation is quite simple at the moment. The q parameter in the Accept header is completely ignored. By default, it tries to abide by the Accept header prioritization inferred from the order of the MIME types in the header. However, you can change it to allow the server ordering, as defined by the order MIME types are added to the MediaTypeFormatMap, to take priority. This was added to work around what I consider to be a bug in Google Chrome - despite being unable to natively render XML, it prioritizes XML over HTML in its Accept header.

Building RestMVC

Hopefully, build.bat should do the trick. RestMVC uses CM.NET, a build library I've developed hosted at The output should be placed in the build directory.

The build will install the RestMvc.Example project as a virtual directory under the Default Web Site and run some functional tests against it. I believe the functional tests will only work on IIS 7 - I think we would need to add a wildcard script map accepting all HTTP verbs on previous versions of IIS.

build.bat /t:Coverage should spit out test coverage in the build directory.

  1. Contributing

Patches and suggestions are always welcome. You can reach me at Feel free to fork the repository at

Something went wrong with that request. Please try again.