Web API OData (OData Client v4) forward slash in key - c#

I have created an OData Web API but I am having problems looking up data where the primary key contains a forward slash.
This url returns data as expected:
/api/SalesOrders('12345')
But this one with the forward slash in the key fails:
/api/SalesOrders('12345/1')
Even when encoded:
/api/SalesOrders('12345%2F1')
In the error presented (see below), it looks like the final forward slash is being converted to a backslash as you would expect because it is part of the url and not in the query string:
If I use the following url instead, where the forward slash is in the querystring, then the data is returned correctly:
/api/SalesOrders?$filter=SalesOrderNumber eq 12345/1
If I were generating the urls myself, this wouldn't be much of an issue.
However, I am using the OData v4 Client Code Generator
So the call in code actually looks like this:
var salesOrder = erpClient.SalesOrders.ByKey(worksOrder.SalesOrderNumber).GetValue();
This generates the url which contains the forward slash before the query string and thus fails.
Is this a known issue with the OData v4 Client?
Is there a setting that forces use of querystring over primary key type calls?
I can work around this by forcing the forward slash into the querystring as follows:
var salesOrder = erpClient.SalesOrders.Where(so => so.SalesOrderNumber == "12345/1" && so.SalesOrderNumber == so.SalesOrderNumber).FirstOrDefault();
This forces the forward slash into the querystring:
/api/SalesOrders?$filter=SalesOrderNumber eq '450993/1' and SalesOrderNumber eq SalesOrderNumber
This feels messy and I would like to avoid moving away from the OData v4 Client as we have several apps that already use it.
Is there anything else I can do to make this work a little neater?
Footnote:
I followed the process on this blog to handle special characters, but this does not include advice on how to handle the forward slash:
using-wcf-data-service-with-restricted-characters-as-keys

Take a look at the ODataPathAndSlashEscapeSample on Github. The basic idea is to subclass DefaultODataPathHandler and override the Parse method. Then provide an instance of your custom path handler to the MapODataServiceRoute method in your Web API configuration code.

This might help anyone looking for a similar solution, just under the 'OData Routing' section...
...To prevent this error, your client should use the double escape sequences for slash (%252F) and backslash (%255C)....

Probably odata is messing up because it can be read litraly
even if it is encoded, my opinion is you must send parameters as an object in the request content.
You can see better http://blogs.msdn.com/b/odatateam/archive/2014/12/08/function-amp-action-in-web-api-v2-2-for-odata-v4-0-type-scenario.aspx#gist16957953
Hope this help

Related

C# HttpClient URI is not escaping properly

I'm trying to get my URL to escape but it's not working properly. Ironically, on my MacBook when I execute this part of code
Uri url = new Uri("http://www.example.com/?i=123%34", true);
// it returns http://www.example.com/?i=123%34 which is exactly what I want.
The problem is that my IDE says it's obsolete and it does not work on my Windows machine. It's the exact same project, and IDE. So I tried to find a solution, which someone suggested
Uri uri = new Uri(Uri.EscapeUriString("http://www.example.com/?i=123%34"));
// this returns http://www.example.com/?i=123%2534 which is what I DONT want.
So how do I approach this issue? I looked all over the web and I can't find any solutions. I need to know how to properly escape this URL. The second method posted above does not work like the first method above.
I verified the GET requests via Fiddler, so everything is indeed happening.
Update:
Again, I need the server to receive the URL exactly how the string is declared. I want the server to handle the conversion. I cannot substitute %25 for the % symbol. It MUST be received exactly how I the string is declared. Additionally, "http://www.example.com/?i=1234" is NOT what I want either.
The problem is with the configuration of your web server on Windows, that allows double escaping. Your original URL is http://www.example.com/?i=123%34, which when unescaped, becomes http://www.example.com/?i=1234.
Your web server on Windows, on the other hand, escapes the % character again instead of unescaping %34. Thus, it turns into http://www.example.com/?i=123%2534.
This is why you should not use characters like % in the URL before it gets escaped.
Edit -
I typed the following two URLs in Firefox to see how the parameters are received on the server.
The value of i in http://www.example.com/?i=123%34 is 1234.
The value of i in http://www.example.com/?i=123%2534 is 123%34
If the server must receive the % character, it must be escaped in order for it to be dispatched over HTTP. There's literally no other way to send it over the wire. If you don't escape the % character, it will be treated as an escape sequence along with 34 and automatically turn into 4 on the server.
If your network inspector shows you unescaped text in the request, it's because it's prettifying the URL before displaying it to you.
If you are okay with the string reading ht tp://www.example.com/?i=1234, you can try
Uri url = new Uri(Uri.UnescapeDataString("http://www.example.com/?i=123%34"));

Rules of url rewriting in asp.net

Is it Required to use '?' sign for query string in Asp.net with C# ?
and can its possible to convert my query string
www.xyz.com/test.aspx?name=rajeev
to
www.xyz.com/rajeev or www.xyz.com/name=rajeev
?name=rajeev is a query string. If you don't use a ? it's not a query string.
/name/rajeev isn't a query string, but it's a path (see ASP.NET routing or IIS URL rewrite module).
/name=rajeev is just a path with a custom way to specify name's value. I would avoid this: you're going to avoid a lot of issues if you choose one of two approaches above.
Also check what saids the URI standard RFC 3986:
[...] The query component is indicated by the first question mark ("?") character and terminated by a number sign ("#") character or by the end of the URI.
That is ? character isn't an ASP.NET requirement if you want to use query strings in your URLs, but it's the standard across all plataforms and languages.
For converting the url www.xyz.com/test.aspx?name=rajeev to www.xyz.com/rajeev
This can be done by Creating Rewrite Rules for the URL Rewrite Module in IIS.
Please read this link.

ExtJS Ajax Proxy - encode extraParams

Consider the following:
var params = Ext.urlDecode(window.location.search);
var store = Ext.getStore("EntryStore");
store.getProxy().extraParams={'mail':params.mail,'id':params.id};
store.load();
when called with
localhost/mypage/?mail=test#mydomain.com&id=QWERTYUIOP/ASDFGHJKL456+yxcvbnm==
queries
localhost/api/?_dc=1387181002249&mail=test#mydomain.com&id=QWERTYUIOP/ASDFGHJKL456+yxcvbnm==&page=1&start=0&limit=25
which contains the reserved character "+" and makes the backend choke on that parameter.
(The C# WebApi backend tells me that the id is
QWERTYUIOP/ASDFGHJKL456 yxcvbnm==, as opposed to the original
QWERTYUIOP/ASDFGHJKL456+yxcvbnm==)
Is
(a) the unencoded "+" sign a bug in sencha or
(b) everything working as intended, and I should read the manual on how to encode my params (please provide a link, I don't find) or
(c) a bug on the Microsoft side causing WebApi to choke on the "+"?
Kind regards,
Alexander
Query strings using the space character need it to be properly encoded. See this answer about that topic.
In short, it's not a bug in Sencha. It's not (necessarily) a bug in your API.
Considering you're using window.location.search to grab the querystring, the issue is that you got to that point without properly encoding the spaces.

How do I use a pattern Url to extract a segment from an actual Url?

If I have a series of "pattern" Urls of the form:
http://{username}.sitename.com/
http://{username}.othersite.net/
http://mysite.com/{username}
and I have an actual Url of the form:
http://joesmith.sitename.com/
Is there any way that I can match a pattern Url and in turn use it to extract the username portion out the actual Url? I've thought of nasty ways to do it, but it just seems like there should be a more intuitive way to accomplish this.
ASP.NET MVC uses a similar approach to extract the various segments of the URL when it is building its routes. Given the example:
{controller}/{action}
So given the Url of the form, Home/Index, it knows that it is the Home controller calling the Index action method.
Not sure I understand this question correctly but you can just use a regular expression to match anything between 'http://' and the first dot.
A very simple regex will do:
':https?://([a-z0-9\.-]*[a-z0-9])\.sitename\.com'
This will allow any subdomain that only contains valid subdomain characters. Example of allowed subdomains:
joesmith.sitename.com
joe.smith.sitename.com
joe-smith.sitename.com
a-very-long-subdomain.sitename.com
As you can see, you might want to complicate the regex slightly. For instance, you could limit it to only allow a certain amount of characters in the subdomain.
It seems the the quickest and easiest solution is going off of Machine's answer.
var givenUri = "http://joesmith.sitename.com/";
var patternUri = "http://{username}.sitename.com/";
patternUri = patternUri.Replace("{username}", #"([a-z0-9\.-]*[a-z0-9]");
var result = Regex.Match(givenUri, patternUri, RegexOptions.IgnoreCase).Groups;
if(!String.IsNullOrEmpty(result[1].Value))
return result[1].Value;
Seems to work great.
Well, this "pattern URL" is a format you've made up, right? You basically you'll just need to process it.
If the format of it is:
anything inside "{ }" is a thing to capture, everything else must be as is
Then you'd just find the start/end index of those brackets, and match everything else. Then when you get to a place where one is, make sure you only look for chars such that they don't match whatever 'token' comes after the next ending '}'.
There are definitely different ways - ultimately though your server must be configured to handle (and possibly route) these different subdomain requests.
What I would do would be to answer all subdomain requests (except maybe some reserved words, like 'www', 'mail', etc.) on sitename.com with a single handler or page (I'm assuming ASP.NET here based on your C# tag).
I'd use the request path, which is easy enough to get, with some simple string parsing/regex routines (remove the 'http://', grab the first token up until '.' or '/' or '\', etc.) and then use that in a session, making sure to observe URL changes.
Alternately, you could map certain virtual paths to request urls ('joesmith.sitename.com' => 'sitename.com/index.aspx?username=joesmith') via IIS but that's kind of nasty too.
Hope this helps!

What's wrong with my url encoding?

In my asp.net mvc application I created the following link:
http://localhost:2689/en/Formula.mvc/351702++LYS+GRONN+5G+9%252f2++fds
I get error 400 (bad request).
I think it blocks at the %25 (forward slash).
What am I doing wrong?
--EDIT 3--
I tried not encoding anything at all but rather rely on the default encoding of Url.RouteUrl().
It seems that this doesn't encode the "/" for some reason.
If I encode it myself first, I end up with the doubel encoded %252f. This gives me a bad request for some reason..
Why?!
--EDIT 2--
I generated the last part of the URI as follows:
Take the id.toString
Take the HttpUtility.UrlEncode(name)
Take the HttpUtility.UrlEncode(code)
String.Format("{0}--{1}--{2}") with the values from the previous parts
Add it as a parameter to Url.RouteUrl()
After that my action gets this parameter again, splits it at -- and HttpUtility.Decode() the values back.
I do it this way because the two last parameters are optional, but functional parameters. IF they are defined in a previous step, they have to be carried along to the other pages.
Less abstract: A color can have multiple names, but if a user selected it by a particular name, it should be kept throughout all the other pages.
--EDIT 1--
It also looks like HttpUtility.UrlEncode() and Url.Encode() return different results :S
If I don't encode the "/", it acts as a separator=>no luck there.
If I encode it with Url.Encode() I end up with %2F => Code 400
If I encode it with HttpUtility.UrlEncode() I end up with %25 => code 400
Because 400 doesn't even let it through to asp.net-mvc, the route debugger is of no use :(
I was there a couple of days ago. If you can accept unreadable route-values in the URL try this:
URL-encoded slash in URL
%25 is actually encoded "%", so %252f is encoded "%2f".
%2f (encoded "/") is not allowed in URL unless you explicitly allow it in webserver's configuration.
Have you run the Routing debugger: http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx
I haven't looked too much at the encoding - but note that if this is to be stored somewhere (or acted upon in some way), then a POST would be more appropriate. If the text on the right is actually representative of the data with id 351702 (a vanity url, much like /665354/whats-wrong-with-my-url-encoding), then you should humanize the text. Much as the spaces have been removed from the above. It is also common to have this as a separate level in the route that is simply discarded.
Generally, MVC urls should be comprehensible.
W3Schools works fine: http://www.w3schools.com/TAGS/html_form_submit.asp?text=hello/world
Here's the URL encoding reference: http://www.w3schools.com/TAGS/ref_urlencode.asp
You can't use a forward slash as a value in the URL. Here is a nice post about creating browser and SEO friendly URLS => http://www.dominicpettifer.co.uk/displayBlog.aspx?id=34
[Edit]
Whenever you create a route you associate it with a URL pattern (The default pattern is {controller}/{action}/{id}). And in this url pattern you are supposed to use the forward slash to separate different tokens. Hope that helps

Categories

Resources