asp.netasp.net-web-apiodataasp.net-web-api-odata

Strongly typed ODataActionParameters possible?


Given the below OData custom action. Is it possible to get a more refactor friendly binding of the action parameters?

Both magic strings has to be exactly the same: .Parameter<int>("Rating") and (int)parameters["Rating"]. Which is bound to break at some point in the future.

Config

ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");

// New code:
builder.Namespace = "ProductService";
builder.EntityType<Product>()
    .Action("Rate")
    .Parameter<int>("Rating");

Controller

[HttpPost]
public async Task<IHttpActionResult> Rate([FromODataUri] int key, ODataActionParameters parameters)
{
    if (!ModelState.IsValid)
    {
        return BadRequest();
    }

    int rating = (int)parameters["Rating"];
    db.Ratings.Add(new ProductRating
    {
        ProductID = key,
        Rating = rating
    });

    try
    {
        await db.SaveChangesAsync();
    }
    catch (DbUpdateException e)
    {
        if (!ProductExists(key))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return StatusCode(HttpStatusCode.NoContent);
}

Request

POST http://localhost/Products(1)/ProductService.Rate HTTP/1.1
Content-Type: application/json
Content-Length: 12

{"Rating":5}

I tried putting the parameter directly in the method. But I couldn't get it to work.

public async Task<IHttpActionResult> Rate([FromODataUri] int key, int rate)

According to How to pass an objet as a parameter to an OData Action using ASP.NET Web Api? it seems it's possible to use an Object but I only have a primitive type as the parameter.

Please advice :)


Solution

  • I think you are talking about this issue https://github.com/OData/WebApi/issues/777

    The ODataActionParameters make thing complicate when there is only one action parameter, we will try to have a workaround or design for this after breaking change 6.0 release.