Currently for every GET I have to manually create a query object from the route parameters.
Is it possible to bind directly to a query object instead?
So, instead of :
[Route("{id:int}")]
public Book Get(int id) {
var query = new GetBookByIdQuery {
Id = id
};
// execute query and return result
}
I could do this:
[Route("{id:int}")]
public Book Get(GetBookByIdQuery query) {
// execute query and return result
}
Where GetBookByIdQuery
looks like:
public class GetBookByIdQuery {
public int Id { get; set;}
}
Web API 2 supports a new type of routing, called attribute routing. As the name implies, attribute routing uses attributes to define routes. Attribute routing gives you more control over the URIs in your web API. For example, you can easily create URIs that describe hierarchies of resources.
The default route template for Web API is "api/{controller}/{id}". In this template, "api" is a literal path segment, and {controller} and {id} are placeholder variables. When the Web API framework receives an HTTP request, it tries to match the URI against one of the route templates in the routing table.
Binding is a process to set values for the parameters when Web API calls a controller action method. Web API methods with the different types of the parameters and how to customize the binding process.
to read a complex type from the URI, [FromUri]
can be used
[Route("{id:int}")]
public Book Get([FromUri] GetBookByIdQuery query) {
// execute query and return result
}
if you request api/values/2 then id property of query object will be 2;
The answer is to define you own HttpParameterBinding
.
Here is the example I've made.
First I've created my CustomParameterBinding
public class CustomParameterBinding : HttpParameterBinding
{
public CustomParameterBinding( HttpParameterDescriptor p ) : base( p ) { }
public override System.Threading.Tasks.Task ExecuteBindingAsync( System.Web.Http.Metadata.ModelMetadataProvider metadataProvider, HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken )
{
// Do your custom logic here
var id = int.Parse( actionContext.Request.RequestUri.Segments.Last() );
// Set transformed value
SetValue( actionContext, string.Format( "This is formatted ID value:{0}", id ) );
var tsc = new TaskCompletionSource<object>();
tsc.SetResult(null );
return tsc.Task;
}
}
The next step is to create custom attribute to decorate parameter:
public class CustomParameterBindingAttribute : ParameterBindingAttribute
{
public override HttpParameterBinding GetBinding( HttpParameterDescriptor parameter )
{
return new CustomParameterBinding( parameter );
}
}
And finally now controller looks like:
public class ValuesController : ApiController
{
// GET api/values/5
[Route( "api/values/{id}" )]
public string Get([CustomParameterBinding] string id )
{
return id;
}
}
So now when I call http://localhost:xxxx/api/values/5
I get: "This is formatted ID value:5"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With