Routing
Wisp supports two routing models - anonymous function route handlers and class-based controllers.
For more info about controllers, see Controllers.
Anonymous Routes
For lightweight applications, Wisp supports defining routes using anonymous functions directly in your Program.cs.
Warning
This feature is currently being reworked. This documentation section describes the new way of functioning that is
currently only available in the nightly branch.
Configuring Routes
Anonymous function based routes are added in the router configuration block.
For example, a Hello World GET handler would look something like this:
The above code will register a GET handler for / that returns the following JSON:
The handler function can be synchronous or async, the ctx parameter is an instance of IHttpContext for the current
request. The expected return for the lambda is object. Any returned object will be serialized into JSON by default, unless
it's a string or a value type. Those will be returned to the client as is.
HTTP Methods
Wisp supports all the current HTTP methods as outlined in RFC 7231
and the new HTTP QUERY Method. The QUERY
method RFC is currently a draft and therefore the Wisp implementation of it may change if the RFC draft changes.
router.Get()
router.Head()
router.Post()
router.Put()
router.Delete()
router.Connect()
router.Options()
router.Trace()
router.Query()
Warning
A note on dependency injection: Every action handler receives an instance of IHttpContext which includes an instance of
IServiceProvider (ctx.Services). This is the correct way of getting dependencies injected into your handler function. Unlike
with class-based controllers, in anonymous handlers, you are responsible for maintaining the correct lifecycle of scoped dependencies.
To correctly inject a scoped dependency, don't forget to create a scope first. And in async contexts, don't forget to use await using.
appBuilder.ConfigureRoutes(router => {
// Synchronously
router.Get("/", ctx => {
using var scope = ctx.Services.CreateScope();
var helloService = scope.GetRequiredService<HelloService>();
return helloService.SayHelloWorld();
});
// Asynchronously
router.Get("/items", async ctx => {
await using var scope = ctx.Services.CreateAsyncScope();
var service = scope.GetRequiredService<ItemService>();
return await service.GetAllAsync();
});
});
Attribute Routing
For controllers, it is usually more convenient to use attribute-based routing.
You can attach one or more [Route] attributes to a controller method to automatically register routes for that method.
[Controller]
public class HelloController : ControllerBase
{
[Route("/")]
[Route("/index")]
public ViewResult GetIndex()
{
return View("index");
}
[Route("/{slug}")]
public ViewResult GetArticle(string slug)
{
var article = articleService.Get(slug);
return View("article", new { Article = article });
}
[Route("/hello/{name}", "POST")]
public ViewResult PostHello(string name, [FromForm] string message)
{
return View("hello", new { Name = name, Message = message });
}
}
The route attribute accepts two arguments - the path and the method.
- The method is optional and defaults to
"GET" - The path is required.
Route Path Syntax
The route path consists of a literal path and any amount of optional variables. The basic
syntax for a path variable is {variableName}.
Optionally, you can specify a type for the variable. If the input doesn't match the type, Wisp
will throw an error. The type is specified after a colon like this: {variableName:int}.
The available types are:
string- String (default)int- integerguid- Guid- more will be added
Greedy Variables
This is a special variable type, denoted with a star ({someVariable:*}). A greedy variable can only exist at the end
of a route, and it consumes everything until the end, including slashes. Greedy variables do not affect query
parameters after a ? in the URL.
For example:
[Route("/api/v1/action/{subAction:*}")] will match all of the following
/api/v1/action/hello/api/v1/action/hello/world/api/v1/action/hello/world/foo
It will not, however, match /api/v1/action
Multiple Routes
If you need your method to match multiple paths, allow multiple methods, or have an optional variable, you can specify
more than one [Route] attribute on it.
For example:
Will match both /hello/world and /hello/world/my-name.
Will match both GET and POST HTTP methods