One of our APIs has a dynamic routing system that invokes a different handler based on attributes of the incoming HTTP request.
Each of these handlers is responsible for building the API response which includes generating hypermedia links that describe the state and capabilities of the resource, for example:
{
"total_count": 3,
"limit": 10,
"from": "2018-01-25T06:36:08Z",
"to": "2018-03-10T07:13:24Z",
"data": [
{
"event_id": "evt_b7ykb47ryaouznsbmbn7ul4uai",
"event_type": "payment.declined",
"created_on": "2018-03-10T07:13:24Z",
"_links": {
"self": {
"href": "https://example.com/events/evt_b7ykb47ryaouznsbmbn7ul4uai"
},
"webhooks-retry": {
"href": "https://example.com/events/evt_b7ykb47ryaouznsbmbn7ul4uai/webhooks/retry"
}
}
},
...
}
To avoid hardcoding paths into these handlers we wanted to take advantage of UrlHelper
to build the links. Unlike many components in ASP.NET Core, this is not something that is injectable by default.
To register it with the built-in container, add the following to your Startup
class:
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddScoped<IUrlHelper>(x => {
var actionContext = x.GetRequiredService<IActionContextAccessor>().ActionContext;
var factory = x.GetRequiredService<IUrlHelperFactory>();
return factory.GetUrlHelper(actionContext);
});
Both IActionContextAccessor
and IUrlHelperFactory
live in the Microsoft.AspNetCore.Mvc.Core package. If you’re using the Microsoft.AspNetCore.All metapackage you should have this referenced already.
Once done, you’ll be able to use IUrlHelper
in any of your components, assuming you’re in the context of a HTTP request:
if (authResponse.ThreeDsSessionId.HasValue)
{
return new PaymentAcceptedResponse
{
Id = id,
Reference = paymentRequest.Reference,
Status = authResponse.Status
}
.WithLink("self", _urlHelper.PaymentLink(id))
.WithLink("redirect",
_urlHelper.Link("AcsRedirect", new { id = authResponse.ThreeDsSessionId }));
}