Skip to content

Instantly share code, notes, and snippets.

@lijunle
Last active August 29, 2015 14:17
Show Gist options
  • Save lijunle/6822123661f3f9582652 to your computer and use it in GitHub Desktop.
Save lijunle/6822123661f3f9582652 to your computer and use it in GitHub Desktop.
Readme for Nancy.AttributeRouting.

Nancy.AttributeRouting

Enable attribute routing for Nancy project, and build route URL with compiled-time checked lambda expression.

Install

PM> Install-Package Nancy.AttributeRouting

Why to use AttributeRouting?

With AttributeRouting, there is no need to write NancyModule, route and content negotiate are handled by attributes.

With AttributeRouting, you can write a clean MVVM (Model - View - View Model) approach with Nancy framework.

Usage Tutorial

The tutorial is to leverage AttributeRouting to build two simple pages.

Todo List Page

The first page to list some todo items in our /todo page.

The following are the corresponding view and view model. (Note: you can use any view engine, I use the default Super Simple View Engine in my example.)

Reference Todo.html

Reference Todo.cs

Notice the Get and View attribute on Todo class constructor:

  • The Get attribute register /todo path on Nancy routing table.
  • The View attribute tells Nancy content negotiate which view template should pick up when requesting HTML.
  • The View attribute path value (Todo) works with Nancy view location convention to find out the proper view template to render. That is /Views/Todo.html in my example.

Create Todo Item Page

Next, we are going to provide a page for creating a new Todo item. The new page is under route path /todo/create.

Reference TodoCreate.html

Reference TodoCreate.cs

  • There is a simple form in the view to post the data back to view model.
  • In the view model, a method with Post attribute is provided to handle the posted request.
  • After added the item to database, the method leverages the injected response to redirect to /toto page.

Link Two Pages

The two pages are separated, it would be better to provide links in pages. So, user can negivate pages by links.

Add create todo items page to todo list page:

Reference Todo_link-page.html

Reference Todo_link-page.cs

Update the redirect url builder in TodoCreate view model:

Reference TodoCreate_link-page.cs

  • Note that we are using IUrlBuilder to construct URL on run time. IUrlBuilder in provided from Nancy.AttributeRouting too. There is no need to configure, it is registed on IoC container by default.
  • Regarding to the APIs of IUrlBuilder, please check the API section below.

Route and View Prefix

You might have notice, both page routing path has a same path /todo. It is a good practice to avoid redundant. Extract them as a route prefix.

Reference TodoBase_prefix.cs

  • Their both same route prefix is extracted to their base class attached RoutePrefix attribute.
  • There is a similiar attrbiute with View attribute named ViewPrefix attribute.
  • You can check the detail APIs of RoutePrefix and ViewPrefix attributes, please check the API section below.

Conclusion

We created two simple pages with Nancy and AttributeRouting. Following MVVM pattern, only models (the IDatabase part), views and view models are created. In the view - view model part, we focus on how the view looks like, what functions we need to provide for the corresponding views.

Routing and view discovering are trivial jobs, use AttributeRouting for them.

Debug

Reference this excellent post to leverage SymbolSource for debugging.

API

RouteAttribute

ViewAttribute

RoutePrefixAttribute

ViewPrefixAttribute

IUrlBuilder

License

MIT License.

// todo view model, place as `/ViewModels/Todo.cs`
public class Todo
{
[Get("/todo")]
[View("Todo")]
public Todo(IDatabase database) // Use IoC to inject dependencies to view model
{
this.Items = database.TodoItems; // get items from database or external data sources
}
public List<string> Items { get; set; }
}
<!-- todo view, place as `/Views/Todo.html` -->
<html>
<body>
<ul>
@Each.Items
<li>@Current</li>
@EndEach
</ul>
</body>
</html>
[RoutePrefix("todo")]
public abstract class TodoBase
{
}
public class Todo : TodoBase
{
[Get("/")]
public Todo(IDatabase database)
{
// ... the code above
}
}
public class TodoCreate : TodoBase
{
[Get("/create")]
public TodoCreate(IDatabase database)
{
// .. the code above
}
[Post("/create")]
public Response Post(IResponseFormatter response, Form form)
{
// ... the code above
}
}
// todo view model, place as `/ViewModels/Todo.cs`
public class TodoCreate
{
private readonly IDatabase database;
[Get("/todo/create")]
[View("TodoCreate")]
public TodoCreate(IDatabase database)
{
this.database = database;
}
[Post("/todo/create")]
public Response Post(IResponseFormatter response, Form form)
{
this.database.TodoItems.Add(form.Content);
return response.AsRedirect("/todo");
}
public class Form
{
public string Content { get; set; }
}
}
<!-- todo view, place as `/Views/TodoCreate.html` -->
<html>
<body>
<form>
<input type="text" name="content" placeholder="Todo Content" />
<input type="submit" />
</form>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment