One of the side projects I created for Web API a while ago was Strathweb.TypeRouting - a little library built on top of the attribute routing extensibility points, that allowed you to declare Web API routes centrally, in a strongly typed way (as opposed to the built in, anonymous object approach).
Then, some time ago, I blogged about how you would achieve the same thing in ASP.NET Core. A bunch of things have changed since then - the original post was written against beta6 of the framework I believe.
Last week, I set up the code on Github, migrated everything to RC2 and released on NuGet for everyone to use.
Installation π
So in short, Strathweb.TypedRouting.AspNetCore is a next incarnation of the Strathweb.TypeRouting library from the ASP.NET Web API world, which enables strongly typed routing in ASP.NET Core MVC projects.
nuget install Strathweb.TypedRouting.AspNetCore -pre
Setup π
In your Startup class, after adding MVC, call opt.EnableTypedRouting(); and then configure your routes:
services.AddMvc();
services.Configure<MvcOptions>(opt =>
{
opt.EnableTypedRouting();
opt.Get("homepage", c => c.Action<HomeController>(x => x.Index()));
opt.Get("aboutpage/{name}", c => c.Action<HomeController>(x => x.About(Param<string>.Any)));
opt.Post("sendcontact", c => c.Action<HomeController>(x => x.Contact()));
});
This creates:
- a GET route to /homepage
- a GET route to /aboutpage/{name}
- a POST route to /sendcontact
All of which go against the relevant methods on our HomeController.
Link generation π
Since the API is fluent, you can also give the routes names so that you can use them with i.e. link generation.
opt.Get("api/values/{id}", c => c.Action<ValuesController>(x => x.Get(Param<int>.Any))).WithName("GetValueById");
Now you can use it with IUrlHelper (it’s a Url property on every controller):
var link = Url.Link("GetValueById", new { id = 1 });
IUrlHelper can also be obtained from HttpContext, anywhere in the pipeline (i.e. in a filter):
var services = context.HttpContext.RequestServices;
var urlHelper = services.GetRequiredService<IUrlHelperFactory>().GetUrlHelper(context);
var link = urlHelper.Link("GetValueById", new { id = 1 });
Finally, you can also use this link generation technique with the built-in action results, such as for example CreatedAtRouteResult:
public IActionResult Post([FromBody]string value)
{
var result = CreatedAtRoute("GetValueById", new { id = 1 }, "foo");
return result;
}
Route constraints π
The library supports two ways of specifying route constraints:
- inline in the template
- via fluent API
The inline constraints are the same as you can use with attribute routing. For example:
opt.Get("api/other/{id:int}", c => c.Action<OtherController>(x => x.Action2(Param<int>.Any)));
You can also specify constraints via the fluent API, by chaining IActionConstraintMetadata implementations. Consider the following sample constraint class:
public class ManadatoryHeaderConstraint : IActionConstraint, IActionConstraintMetadata
{
private string _header;
public ManadatoryHeaderConstraint(string header)
{
_header = header;
}
public int Order => 0;
public bool Accept(ActionConstraintContext context)
{
// only allow route to be hit if the predefined header is present
if (context.RouteContext.HttpContext.Request.Headers.ContainsKey(_header))
{
return true;
}
return false;
}
}
You can now use this class in the route declaration:
opt.Get("api/other", c => c.Action<OtherController>(x => x.Action1())).WithConstraints(new ManadatoryHeaderConstraint("CustomHeader"));
Contribute π
If you have any ideas, suggestions or want to help - please visit Github. Thanks!