Search code examples
c#asp.net-mvcasp.net-web-api2odata

Can't get ODATA v4 actions attached to an entity to work


So, I tried following the instructions here to implement an action on my Job entity, but for the life of me, I can't get OData to recognize it.

The Action is pretty simple. Just a toggle for a boolean:

[HttpPost]
public IHttpActionResult Pause([FromODataUri]int key)
{
    if (!ModelState.IsValid)
    {
         return BadRequest();
    }

    Job job = _context.Job.Find(key);
    if (job == null)
    {
        return NotFound();
    }

    job.IsPaused = !job.IsPaused;
    _context.SaveChanges();

    return Ok(acquisition.IsPaused);
}

And it is defined in my WebApiConfig as:

var jobEntity = builder.EntityType<Job>();
var pause = jobEntity.Action("Pause");
pause.Returns<bool>();

So, I should be able to POST to //url/odata/Job(key)/Pause to call it. Unfortunately, it doesn't recognize the Pause action, listing it with a response of entityset/key/unresolved action. If I try to use the ODataRoute attribute on it:

[ODataRoute("Job({key})/Pause")]

It chokes on the Pause, giving me a compile error of "The path template 'Job({key})/Pause' on the action Pause in controller 'Job' is not a valid OData path template. Found an unresolved path segment 'Pause' in the OData path template."

Now, if I make it an unbound action:

var pause = builder.Action("Pause");
pause = Parameter<int>("key");
pause.Returns<bool>();

and

[HttpPost]
[ODataRoute("Pause")]
public IHttpActionResult Pause(ODataActionParameters parameters)
{
    if (!ModelState.IsValid)
    {
         return BadRequest();
    }

    var key = Convert.ToInt32(parameters["key"]);
    Job job = _context.Job.Find(key);
    if (job == null)
    {
        return NotFound();
    }

    job.IsPaused = !job.IsPaused;
    _context.SaveChanges();

    return Ok(acquisition.IsPaused);
}

It works just fine. So, why can't I bind this to the Job entity? Just as a note I did try adding ODataActionParameters, even tho I don't have any parameters to see if that changed anything. It didn't.


Solution

  • FYI the bound to entityset examples, from that, you can see that you need a namespace, you should request like: odata/Job(key)/Default.Pause, bound action doesn't need ODataRoute.