I am having some trouble in generating WebAPI hypermedia links in a project I am working on.
In the code snippet below the extension methods Order
, OrderUpdate
and OrderDelete
for individual orders are all returning Null links. I suspect this is because WebAPI is unable to resolve these inner routes from the parent Orders
route.
I am not certain why Null links are being returned as I am supplying valid route names to the Link
method.
You can see from the resulting JSON output that the Uri
elements are all Null
for the Links
array element within the Order
object.
// WebApiConfig.cs
config.Routes.MapHttpRoute(
name: "Orders",
routeTemplate: "api/orders",
defaults: new { controller = "order", action = "get" },
constraints: new { httpMethod = new HttpMethodConstraint( HttpMethod.Get ) }
);
config.Routes.MapHttpRoute(
name: "Order",
routeTemplate: "api/orders/{orderid}",
defaults: new { controller = "order" },
constraints: new { orderid = "^[0-9]+$", httpMethod = new HttpMethodConstraint( HttpMethod.Get ) }
);
config.Routes.MapHttpRoute(
name: "OrderUpdate",
routeTemplate: "api/orders/{orderid}",
defaults: new { controller = "order", action = "put" },
constraints: new { orderid = "^[0-9]+$", httpMethod = new HttpMethodConstraint( HttpMethod.Put ) }
);
// OrderController.cs
public async Task<Orders> Get()
{
var orders = new Orders();
orders.Links.OrderList( Url, "self" ); // returns a link OK
orders.Links.OrderAdd( Url, "order-create" ); // returns a link OK
foreach ( var order in await _repository.GetOrders() )
{
order.Links.Order( Url, "self", order.Id ); // returns NULL
if ( !User.IsInRole( "Readonly" ) )
{
order.Links.OrderUpdate( Url, "order-update", order.Id ); // returns NULL
order.Links.OrderDelete( Url, "order-delete", order.Id ); // returns NULL
}
orders.Order.Add( order );
}
return orders;
}
// LinkGenerationExtensions.cs
public static void Order( this List<Link> @this, UrlHelper url, string rel, int orderId )
{
@this.Add( new Link { Rel = rel, Uri = url.OrderUri( orderId ) } );
}
public static string OrderUri( this UrlHelper url, int orderId )
{
return url.Link( "Order", new { id = orderId } );
}
public static void OrderList( this List<Link> @this, UrlHelper url, string rel )
{
@this.Add( new Link { Rel = rel, Uri = url.OrderListUri() } );
}
public static string OrderListUri( this UrlHelper url )
{
return url.Link( "Orders", new { } );
}
public static void OrderUpdate( this List<Link> @this, UrlHelper url, string rel, int orderId )
{
@this.Add( new Link { Rel = rel, Uri = url.OrderUpdateUri( orderId ) } );
}
public static string OrderUpdateUri( this UrlHelper url, int orderId )
{
return url.Link( "OrderUpdate", new { id = orderId } );
}
The above code generates the following JSON response:
{
"Order": [
{
"Id": 4,
"OrderRef": 123456,
"OrderDate": "2015-02-04T10:28:00",
"CustomerName": "ACME Construction Ltd",
"OrderedBy": "PA",
"InstallationDate": "2015-06-15T00:00:00",
"Address": "900 ACME Street",
"Postcode": "SW2 7AX",
"Town": "London",
"OrderNumber": "6508756191",
"Value": 525,
"Invoice": 0,
"Links": [
{
"Rel": "self",
"Uri": null
},
{
"Rel": "order-update",
"Uri": null
},
{
"Rel": "order-delete",
"Uri": null
}
]
}
],
"Links": [
{
"Rel": "self",
"Uri": "http://localhost/Site/api/orders"
},
{
"Rel": "order-create",
"Uri": "http://localhost/Site/api/orders/add"
}
]
}