Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebApi attribute routing - Bind route parameter to an object for GETs

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;}
}
like image 447
kimsagro Avatar asked Jul 26 '15 03:07

kimsagro


People also ask

Which attribute is used to define routes in Web API?

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.

How do I specify a route in Web API?

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.

What is parameter binding in Web API?

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.


2 Answers

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;

like image 88
MstfAsan Avatar answered Oct 30 '22 21:10

MstfAsan


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"

like image 21
Enes Avatar answered Oct 30 '22 23:10

Enes