Adding manually defined service operations inside initService for odata service

StackOverflow https://stackoverflow.com/questions/17329915

  •  01-06-2022
  •  | 
  •  

Question

I have a WebApi controller derived from ApiController that has a service operation:

 public class Airports2Controller : ApiController
    {
        protected airportEntities db = new airportEntities ();

         [Queryable]
        [HttpGet]
        public IQueryable<Airport> GetAirportsWithinRadius(int airportId, int radius)
        {
            //var radius = (int)parameters["radius"];
            //var airportId = (int)parameters["airportId"];

            var resultAirports = GetAirportsWithinRadius2(airportId, radius);

            return resultAirports;            
        }


        private IQueryable<Airport> GetAirportsWithinRadius2(int airportId, int radius)
        {
            var airports = db.Airports.SqlQuery("select * from Airport a where (select GeoLocation from airport where Id = @p0).STDistance(a.GeoLocation)/1.852/1000.00 < @p1", airportId, radius);

            var airportIds = airports.Select(a => a.Id);
            var resultAirports = db.Airports.Where(a => airportIds.Contains(a.Id));

            return resultAirports;
        }
    }

I also have an odata service for the Airport entity. Since .net webapi odata doesn't yet have support for odata functions (service operations?), I needed to create a secondary controller (that's not derived from ODataController).

What I want to do now with jaydata is to extend the context to have the service operation in addition to the odata stuff, once the db is initialized in initService:

$data.initService("http://localhost:2663/odata");
            service.then(function (db) {
        //now here manually extend the definition of the context to include the GetAirportsWithinRadius service operation.
});

}

This controller works nicely with get parameters and returns the correct json when manually invoked from fiddler. How do extend the jaydata context to have a GetAirportsWithinRadius(airportId,radius) method? Its url will need to be set manually and its type will need to be changed to GET. Also, will that method then be composable with odata params since it is declared with [Queryable]. Again that part of it works when manually invoked in fiddler. For example:

http://localhost:2663/api/Airports2/GetAirportsWithinRadius?airportId=2112&radius=50&?$inlinecount=allpages&$top=2

This returns two airport entity objects nicely...

Thanks

Was it helpful?

Solution

Thanks @robesz - there were some subtleties in creating parameterized odata actions in .net and this is what has been plaguing me (I have tried actions before just couldn't get it to work), but this time I got it:

 [Queryable]
        [HttpPost]
        public IQueryable<Airport> GetAirportsWithinRadius([FromBody] ODataActionParameters parameters)
        {
            if (!ModelState.IsValid)
            {
                throw new HttpResponseException(HttpStatusCode.BadRequest);
            }
            var radius = (int)parameters["radius"];
            var airportId = (int)parameters["airportId"];

            var resultAirports = GetAirportsWithinRadius2(airportId, radius);

            return resultAirports;            
        }

 ActionConfiguration getAirportsWithinRadius = modelBuilder.Entity<Airport>().Collection.Action("GetAirportsWithinRadius");
            getAirportsWithinRadius.Parameter<int>("airportId");
            getAirportsWithinRadius.Parameter<int>("radius");
            getAirportsWithinRadius.ReturnsCollectionFromEntitySet<Airport>("Airports");

With this in place I can now do the following with jaydata:

var service = $data.initService("http://localhost:2663/odata");
        return service.then(function (db) {
           airports = db.Airports.GetAirportsWithinRadius(2112,50);
           airports.filter("it.Abbrev== a", {a: 'C44'}).forEach(function(a){console.log(a.Abbrev)});
    });

I am jumping up and down in joy :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top