I have a Web Api endpoint which is currently called like this:
http://api.example.com/scenes?creationDate=1440091949
I am trying to support more complex queries such as:
http://api.example.com/scenes?creationDate.lt=1440091949
Note the .lt
suffix. This would let the user to list all the scenes in which creationDate
is less than (lt) than 1440091949
.
For this, I had to create my own mapper function which would map each query parameter to a query model's properties and store each query operation (lt, gt, eq, etc...) in a dictionary of operations:
protected QueryData MapToQueryData(IEnumerable<KeyValuePair<string, string>> queryParameters)
{
QueryData queryData = new QueryData();
foreach(var queryParam in queryParameters)
{
string[] segments = queryParam.Key.Split('.'); // ["creationDate", "lt"]
if(!segments.Any()) continue;
PropertyInfo queryProperty = _reflection.Properties.GetProperty<QueryData>(segments.First()); // "CreationDate" Property
if(queryProperty == null) continue;
object value = _reflection.Conversion.ConvertTo(queryParam.Value, property.PropertyType); // Convert 1440091949 to long
if(value == null) continue;
_reflection.Properties.SetPropertyValue(queryData, property, value); // Set queryData.CreationDate = 1440091949
if(segments.Length < 2) continue;
PropertyInfo mapProperty = _reflection.Properties.GetPropertiesWithAttribute<QueryData, OperationMapAttribute>().FirstOrDefault(); // Identify Property annotated with [OperationMap]
if(mapProperty == null) continue;
Dictionary<string, string> operationMap = _reflection.Properties.GetPropertyValue(queryData, mapProperty) as Dictionary<string, string>(); // Get dictionary from Map property
if(operationMap == null) continue;
if(!operationMap.ContainsKey(property.Name))
operationMap.Add(property.Name, segments.Last()); // "creationDate" -> "lt"
else
operationMap[property.Name] = segments.Last();
_reflection.Properties.SetPropertyValue(queryData, mapProperty, operationMap); // Set Map property of QueryData to the updated dictionary
}
return queryData;
}
I know there exists an automatic mapping provided by ASP.NET Web Api if one decides to use the [FromUri]
attribute, but that would work if I had simple query parameters such as creationDate=1440091949
, but will not work if I send a query parameter such as creationDate.lt=1440091949
.
Is there something built in, in the Web APi engine to handle these types of query parameters? I have seen them on a lot of web services, so they are pretty common for ordering or doing complex queries.
Best way to pass multiple complex object to webapi services is by using tuple other than dynamic, json string, custom class. No need to serialize and deserialize passing object while using tuple. If you want to send more than seven complex object create internal tuple object for last tuple argument.
To force Web API to read a complex type from the URI, add the [FromUri] attribute to the parameter. The following example defines a GeoPoint type, along with a controller method that gets the GeoPoint from the URI.
The [FromUri] attribute is prefixed to the parameter to specify that the value should be read from the URI of the request, and the [FromBody] attribute is used to specify that the value should be read from the body of the request.
Query String Parameters is an important concept in .NET programming. Let us learn how to use query string parameters in ASP.NET Web API programming. Follow the steps mentioned below. Open SQL Server 2014 or a version of your choice, create a table, and insert some records. CREATE TABLE [dbo]. [Employees] (
Use [FromUri] attribute to force Web API to get the value of complex type from the query string and [FromBody] attribute to get the value of primitive type from the request body, opposite to the default rules. For example, consider the following GET method.
Action methods in Web API controllers can have one or more parameters of different types. It can be either primitive type or complex type. Web API binds action method parameters with the URL's query string or with the request body depending on the parameter type.
The item parameter is a complex type, so Web API uses a media-type formatter to read the value from the request body. To get a value from the URI, Web API looks in the route data and the URI query string.
Have you tried using something like the OData query syntax?
http://blogs.msdn.com/b/martinkearn/archive/2015/03/10/using-odata-query-syntax-with-web-api.aspx
From the aforementioned...
OData query syntax is a standard way of querying RESTful APIs using a pre-defined syntax that allows the calling client to define the sort order, filter parameters and pages of data that is returned.
The full syntax can be found in section 5 of the OData Version 4.0 Part 2 specification but here are some quick examples of how the syntax is used:
This is where things get really awesome - it is super, super easy to change a regular Web API controller to support OData query syntax - once you know how to do this, you'll never not do it!
If we assume we are starting from a regular Web API project (File > New Project > ASP.net Web Application > Web API), you first need to add a scaffolded controller which you can do by following these steps:
NOTE: You do not need to choose the 'Web API 2 OData Controller...' option, you can add the query syntax to any controller
Once you've setup your controller, you should end up with a simple controller which has a default GET action that looks a little like this:
// GET: api/People
public IQueryable<Person> GetPeople()
{
return db.People;
}
This action will simply return all the rows in the 'People' table of the database with no ability to filter, sort etc. To add full OData query support, you need to make a few changes:
Your finished code will look something like this:
// GET: api/People
[EnableQueryAttribute]
public IQueryable<Person> GetPeople()
{
return db.People.AsQueryable();
}
That is all there is to it! .... now you have this setup, you can use the full OData syntax to query sort etc without any extra code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With