Search code examples
c#asp.net-web-apiodataurlencode

OData filter options fail when Uri has escaped ampersand


I'm currently using OData v3, but this seems to fail (just differently) in OData v4 as well.

Let's say I have the following Uri:
http://myurl.com/odata/SomeEndpoint?$filter=FieldId eq 1&$top=10

Perfect, type that into Postman or a browser, works great. But If I encode the Uri it fails.

HTML Encoding:
http://myurl.com/odata/SomeEndpoint?$filter=FieldId eq 1&$top=10

Everything before the escaped character will get applied to the query (so $filter still works), but everything after the escaped character is ignored ($top is not applied).

URI Encoding (I tried both):
http://myurl.com/odata/SomeEndpoint?$filter=FieldId eq 1%26$top=10 http://myurl.com/odata/SomeEndpoint?$filter=FieldId eq 1%26%$top=10

Both cause OData to throw an exception when trying to apply the query options with the following error (paraphrased since this is from memory):

'&' is in invalid character in query string.
$filter=FieldId eq 1&$top=10

As you can see, this is undesired and an issue. If my client's encode their Uri before sending a request it won't work. Also, the links generated by OData in the result are encoded, for instance, the next page link:

<link rel="next" href="http://myurl.com/odata/SomeEndpoint?$filter=FieldId%20eq%201&amp;$skip=1" />

OData doesn't seem to mind the %20 (space) that works fine, but $skip is actually ignored because of the escaped ampersand (&amp;) if you just change it to a real ampersand (&) it works fine.

Is there a way to fix this? It seems to be an issue with OData.

For reference here is how I'm mapping my routes:

#pragma warning disable CS0618 // OData v3 route mapping.
config.Routes.MapODataRoute(
    routeName: "odata",
    routePrefix: "odata",
    model: model);
#pragma warning restore CS0618

I'm not doing anything custom.

UPDATE:
When I set my ACCEPT header to XML I get:
<link rel="next" href="http://myurl.com/odata/SomeEndpoint?$filter=FieldId%20eq%201&amp;$skip=1" />

When I set my ACCEPT header to JSON I get:
odata.nextLink": "http://webapi.mydlweb.com/api/test/odata/v3/Checks?$filter=StoreId%20eq%2040&pagesize=1&$skip=1"

Per the comment below, the JSON link is generated correctly. I can click it and it works because the ampersand is not encoded. However the XML link DOES encode the ampersand and is thus causing it to not work. Is that normal when encoding XML then? How then does the client know which ampersands to "unencode" and which to leave encoded? For instance, if you use an ampersand inside of a filter (not to separate query strings) then it DOES need to be encoded.

UPDATE 2: I guess it is XML encoding, and that's just the way it is.

enter image description here


Solution

  • You can't escape the ampersand in a querystring and expect it to behave like an unescaped ampersand in a querystring. This doesn't have anything to do with odata, just normal querystring behavior. By escaping it, the parser will not interpret it as a delimiter of key/value pairs but as a literal ampersand in the value.

    EXAMPLE: This google search works:

    https://www.google.com/search?safe=off&q=test
    

    But, this one does not:

    https://www.google.com/search?safe=off%26q=test