I have a working (simplified) ODataController
with the following method.
public class MyTypeController : ODataController
{
[HttpGet]
[EnableQuery]
[ODataRoute("myTypes")]
public IQueryable<MyType> GetMyTypes(ODataQueryOptions<MyType> options)
{
return _repo.myResultsAsQueryable();
}
}
I would like to be able to call this method from the server and to do this I need to instantiate an ODataQueryOptions
which requires an ODataQueryContext
.
There are examples of how to do this (Eg. here and here) but they all seem to reference a previous version of OData. The ODataQueryContext constructor currently requires a third argument (ODataPath
path) which is not addressed in any examples that I can find.
Edit: @snow_FFFFFF, Here's some more context... I realize that I can simply consume the OData endpoint via a HttpClient but I would like to interact with the IQueryable directly as you say.
The problem is that the application I'm working on allows users to create filters (like a sophisticated search engine) that can be saved and later recalled by other users. From a JS client, they simply lookup the filter by id, and issue a query against the OData endpoint with the filter applied to the query string. This works very well from the client-side but I would like to be able to do something similar from the server-side as well.
This is what I would like to do but how can I instantiate the ODataPath argument?
public IQueryable<MyType> FilterMyTypes(int filterID)
{
// lookup filter by filterID from db...
filter = "$filter=Status eq 1"; // for example...
ODataPath path = // but how can I get the path!!!
new ODataQueryContext(edmModel, typeof(MyType), path);
var uri = new HttpRequestMessage(HttpMethod.Get, "http://localhost:56339/mytypes?" + filter);
var opts = new ODataQueryOptions<MyType>(ctx, uri);
var results = new MyTypeController().GetMyTypes(opts);
}
Another application of this would be to support dynamic grouping as below:
[HttpGet]
[Route("myTypes/{filterID:int}/groupby/{groupByFieldName}")]
public IHttpActionResult GroupMyTypes(int filterID, string groupByFieldName)
{
// For example: get all Active MyTypes and group by AssignedToUserID...
// Get the results of the filter as IQueryable...
var results = FilterMyTypes(filterID);
// group on groupByFieldName
var grouped = results.GroupBy(x => GetPropertyValue(x,groupByFieldName));
// select the groupByFieldName and the count
var transformedResults = grouped.Select(g => new { g.Key, Count = g.Count() });
return Ok(transformedResults);
}
Sure. ODataPath is a list of ODataPathSegment(s) which should follow up the OData Uri spec.
In Web API OData, it's easy to instantiate an ODataPath, for example:
IEdmModel model = GetEdmModel();
IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet(setName);
ODataPath path = new ODataPath(new EntitySetPathSegment(entitySet));
The above path
follows up the OData spec that it has the odata template as:
~/entityset
More test cases (codes) can be found here
Your odata controller is providing an HTTP interface to your data, shouldn't you access it via HTTP (even if from the server)? There is a VS add-in to generate odata client code here:
https://visualstudiogallery.msdn.microsoft.com/9b786c0e-79d1-4a50-89a5-125e57475937
Or, if you are doing this from within the same project, why not a common method that returns the IQueryable that could be called from your code or from the controller?
UPDATE: Based on more information in the original question:
If you have ODataQueryOptions defined in a controller method, it will allow you to parse the well-formed odata query that is calling that method. I have used this when I needed to translate parts of an odata query because I needed to query multiple data sources to return the final result.
It sounds like you want something that takes non-odata parameters and options. For this, you probably need to look at custom Actions and or Functions (if you are just returning data, probably a function):
UPDATE #2: And after more detailed reading, I think I missed your point - I don't have the answer, but I'll play around with it. Can't you just reform the URL itself (as opposed to instantiating the query options?
UPDATE #3: I think you are going to have a hard time tricking it into thinking it is getting an odata request...that isn't really an odata request. Back to the second option mentioned in my original answer - why not a common method that you can use and the odata controller can use - something like this:
// some sort of helper class
public class HelperObject
{
public static IQueryable<MyType> GetGroupedValues(int filterID, string groupByFieldName)
{
// all your code/logic here
}
}
// your odata controller uses the helper
[HttpGet]
[Route("myTypes/{filterID:int}/groupby/{groupByFieldName}")]
public IHttpActionResult GroupMyTypes(int filterID, string groupByFieldName)
{
return Ok(HelperObject.GetGroupedValues(filterID, groupByFieldName));
}
// ... and so does your other code that wants to do the same thing
var x = HelperObject.GetGroupedValues(filterID, groupByFieldName);
来源:https://stackoverflow.com/questions/33572659/how-to-instantiate-odataqueryoptions