20

Is it possible to get OData to do the following? I would like to be able to query a REST call by passing on parameters that may not be the primary key. Can I call a REST method like --> GetReports(22, 2014) or Reports(22, 2014)?

[HttpGet]
[ODataRoute("Reports(Id={Id}, Year={Year})")]
public IHttpActionResult GetReports([FromODataUri]int Id, [FromODataUri]int Year)
{
    return Ok(_reportsRepository.GetReports(Id, Year));
}

Here is my latest change.

//Unbound Action  OData v3
var action = builder.Action("ListReports");
action.Parameter<int>("key");
action.Parameter<int>("year");
action.ReturnsCollectionFromEntitySet<Report>("Reports");

my method for controller ReportsController

[HttpPost]
[EnableQuery]
public IHttpActionResult ListReports([FromODataUri] int key, ODataActionParameters parameters)
{
    if (!ModelState.IsValid)
    {
        throw new HttpResponseException(HttpStatusCode.BadRequest);
    }

    int year = (int)parameters["year"];
    
    return Ok(_reportsRepository.GetReports(key, year).Single());
}

I tried calling the url like:

http://localhost:6064/odata/Reports(key=5,year=2014)/ListReports

No HTTP resource was found that matches the request URI 'http://localhost:6064/odata/Reports(key%3D5%2Cyear%3D2014)/ListReports'.`

2 Answers 2

33

You can define a function import named GetReports that has two parameters.

(Note: the name of the function import can't be the same with entity set name)

Configure your EDM model as:

var builder = new ODataConventionModelBuilder();
builder.EntitySet<Report>("Reports");
var function = builder.Function("GetReports");
function.Parameter<int>("Id");
function.Parameter<int>("Year");
function.ReturnsCollectionFromEntitySet<Report>("Reports");
var model = builder.GetEdmModel();

And then write your method as:

[HttpGet]
[ODataRoute("GetReports(Id={Id},Year={Year})")]
public IHttpActionResult WhateverName([FromODataUri]int Id, [FromODataUri]int Year)
{
    return Ok(_reportsRepository.GetReports(Id, Year));
}

Then the request

Get ~/GetReports(Id=22,Year=2014)

will work.

Sign up to request clarification or add additional context in comments.

10 Comments

How can this be done with Odatav3? v3 does not have a function.
I have to use Odata v3 because I am using Jaydata and it sems to only work with v3. If I use Jaydata with Odata v4 it raises a 404 error. Any solution with v3?Thanks
With v3, you can define an action. If you define an unbound action, you have to use HttpPost and pass the parameters through the request body, and you need to add a method "HandleUnmappedRequest" in the controller to match the unbound action request. If you define it as a bound action bound to entity set although this doesn't make sense, you can add a method "[ActionName]OnCollectioinOf[EntityTypeName]" and call HttpPost "~/[EntitySetName]/[ActionName]", and pass the parameters in the request body.
Thanks Feng. Do you have an example somewhere that I can look at? Any blogs showing how to create an unbound action?
|
3

For OData v4.0 endpoints, you don't have to make it a function, you can simply do...

public class ReportsController : ODataController
{
    [EnableQuery]
    [ODataRoute("Reports({id}, {year})")]
    public IQueryable<ReportModel> Get([FromODataUri] int id, [FromODataUri] int year)
    {
        ...
    }
}

Then you can call it like...

/Reports(42, 2019)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.