Couple of days ago, I wrote a blog post on complex type action parameters and controller action selection with ASP.NET Web API with a solution that I’ve come up with and I encourage you to check that blog post out to get a sense of what this is really about. However, that solution was sort of noisy. Yesterday, I tweaked the ComplexTypeAwareActionSelector implementation a bit and now it directly supports the complex type action parameters without any additional attributes for the action methods. In this post, we will see how we can use it and in the next post, we will see how it works under the covers.
First of all, install the latest WebAPIDoodle package rom the Official NuGet feed:
PM> Install-Package WebAPIDoodle
Let’s go through the scenario briefly. Assume that we have the following controller with two action methods that are expected to serve for different GET requests:
public class CarsByCategoryRequestCommand { public int CategoryId { get; set; } public int Page { get; set; } [Range(1, 50)] public int Take { get; set; } } public class CarsByColorRequestCommand { public int ColorId { get; set; } public int Page { get; set; } [Range(1, 50)] public int Take { get; set; } } [InvalidModelStateFilter] public class CarsController : ApiController { public string[] GetCarsByCategoryId( [FromUri]CarsByCategoryRequestCommand cmd) { return new[] { "Car 1", "Car 2", "Car 3" }; } public string[] GetCarsByColorId( [FromUri]CarsByColorRequestCommand cmd) { return new[] { "Car 1", "Car 2" }; } }
If we now send a GET request to /api/cars?colorId=23&page=2&take=12 with the default action selector registered, we would get the ambiguity error message because the default action selector doesn’t consider the complex type action parameters while performing the action selection.
Let’s replace the default action selector with our ComplexTypeAwareActionSelector as below. Note that ComplexTypeAwareActionSelector preserves all the features of the ApiControllerActionSelector.
protected void Application_Start(object sender, EventArgs e) { var config = GlobalConfiguration.Configuration; config.Routes.MapHttpRoute( "DefaultApiRoute", "api/{controller}/{id}", new { id = RouteParameter.Optional } ); // Replace the default action IHttpActionSelector with // WebAPIDoodle.Controllers.ComplexTypeAwareActionSelector config.Services.Replace( typeof(IHttpActionSelector), new ComplexTypeAwareActionSelector()); }
As explained inside the previous related post, we previously had to mark the action methods with UriParametersAttribute to give a hint about the action parameters we want to support. However, with the current implementation of the the ComplexTypeAwareActionSelector, it just works as it is. Only thing required to perform is to mark the complex action parameter with FromUriAttribute. By marking the complex type parameters with FromUriAttribute, you are making it possible to bind the route and query string values.
After replacing the default action selector with our own implementation, we will see it working if we send a GET request to /api/cars?colorId=23&page=2&take=12.
Now, let’s send a request to /api/cars?categoryId=23&page=2&take=12 and see what we will get back:
Working perfectly as expected. The ComplextTypeAwareActionSelector considers simple types inside a complex type parameter which are all primitive .NET types, System.String, System.DateTime, System.Decimal, System.Guid, System.DateTimeOffset, System.TimeSpan and underlying simple types (e.g: Nullable<System.Int32>).
In the next post, we will see how ComplextTypeAwareActionSelector works and behaves with complex type action parameters. Stay tuned! ;)