McDuff
McDuff

Reputation: 45

Web API, OData Passing in multiple parameters in GET operation

Hoping someone can hepl with an issue I've been having. I've created a Web API that fetches records from the a database. I have the following functions in place which work ok:

localhost:8080/api/Budgets -- Returns all Budgets

localhost:8080/api/Budgets(799) -- Returns all for contract 799

What I'm looking for is to be able to pass in two parameters to allow me to do calulations on the records retrieved so something like:

localhost:8080/api/Budgets(799)/215 -- Where 799 is the contract Number and 215 is a material number.

This will allow me to return a dataset of only materials for that budget that I can then do calculations on. There is only one SQL table for this which contains both the contract number and material number as well as a load of other figures.

Here's what I have so far but it doesnt seem to be working:

    public IHttpActionResult Get()
    {
        return Ok(context.Budgets);
    }

    public IHttpActionResult Get([FromODataUri] int key)
    {
        var budgets = context.Budgets.FirstOrDefault(p => p.ProjectNo == key);
        if (budgets == null)
        {
            return NotFound();
        }
        return Ok(budgets);
    }

[ODataRoute("GetMaterialUsage(ProjectId={ProjectId},ResourceCode={ResourceCode})")]
        public IHttpActionResult GetMaterialUsage([FromODataUri] int ProjectId, [FromODataUri] string ResourceCode)
        {
            var budgets = context.Budgets.FirstOrDefault(p => p.ProjectNo == ProjectId && p.ResourceCode == ResourceCode);
            if (budgets == null)
            {
                return NotFound();
            }
            return Ok(budgets);
        }

WebApiConfig:

            ODataModelBuilder builder = new ODataConventionModelBuilder();

        // Web API configuration and services
        builder.EntitySet<BudgetTypes>("BudgetTypes");
        builder.EntitySet<Budgets>("Budgets");
        var function = builder.Function("GetMaterialUsage");
        function.Parameter<int>("ProjectId");
        function.Parameter<string>("ResourceCode");
        function.ReturnsCollectionFromEntitySet<Budgets>("Budgets");


        // Web API routes
        config.MapHttpAttributeRoutes();

        config.MapODataServiceRoute(
            routeName: "ODataRoute",
            routePrefix: "api",
            model: builder.GetEdmModel()
        );

Can anyone shine some light on how this can be done? I just want to pass 2 parameters to a function from the url.

At the moment the following links return 404: localhost:8080/api/Budgets(752,230) localhost:8080/api/Budgets(ProjectNo=752,ResourceCode=230)

Upvotes: 0

Views: 3743

Answers (2)

Fan Ouyang
Fan Ouyang

Reputation: 2142

you have specify the ODataRoute:

[ODataRoute("GetMaterialUsage(ProjectId={ProjectId},ResourceCode={ResourceCode})")]

And second parameter is string, so you should call like

localhost:8080/api/GetMaterialUsage(ProjectNo=752,ResourceCode='230')

If you need something like your not-working url, you need bound this function to your entity Budget, you will know how to do it refer to this page: http://odata.github.io/WebApi/#04-06-function-parameter-support

Upvotes: 1

Nez
Nez

Reputation: 55

I'm not 100% sure on this answer, because I've used OData a little differently, but I think the principle is still the same; I believe the key is to add a 2nd nullable parameter to your 2nd Get function...

//try: localhost:8080/api/Budgets(799,251)
//use this in-place of your second get function
//note the nullable (optional) 2nd parameter
public IHttpActionResult Get([FromODataUri] int key, [FromODataUri] int? key2 = null)
{
    if (key2 == null)
    {
        //carry-on as usual using the 1-param code
        var budgets = context.Budgets.FirstOrDefault(p => p.ProjectNo == key);
        if (budgets == null)
        {
            return NotFound();
        }
        return Ok(budgets);
    }
    else
    {
        //if a second param is also supplied...

    }
}

Upvotes: 0

Related Questions