As part of a custom log in page, I'm trying to get the querystring part of a URL string that may represent an absolute or a relative URL. If it's an absolute URL, I can use use the Uri.Query property, but this is not supported for relative URLs.
Is it as simple as getting the substring starting at the first instance of a '?' or is it possible for a URL to contain a question mark before the query string? Or can any other text come after the query string?
returnUrl.Substring(returnUrl.IndexOf('?'))
Where returnUrl may be absolute: "http://www.example.com/anydir/any-page1?param=1" or relative: "/anydir/any-page?param=1"
Only the first question mark in the URL has significance to indicate the start of the query string. Any after it are treated as a literal question mark.
See RFC 3986 3.4 and 3.3
It does note however:
The characters slash ("/") and question mark ("?") are allowed to
represent data within the fragment identifier. Beware that some
older, erroneous implementations may not handle this data correctly
when it is used as the base URI for relative references
Related
Is it safe to use an # symbol as part of a user? For example, a possible URL would be http://example.com/#dave.
The idea is that, nowadays, users are commonly called "#user", so why not make the user page "#username"?
Percent-encoded …
You can use the # character in HTTP URI paths if you percent-encode it as %40.
Many browsers would display it still as #, but e.g. when you copy-and-paste the URI into a text document, it will be %40.
… but also directly
Instead of percent-encoding it, you may use # directly in the HTTP URI path.
See the syntax for the path of an URI. Various unrelated clauses aside, the path may consist of characters in the segment, segment-nz, or segment-nz-nc set. segment and segment-nz consist of characters from the pchar set, which is defined as:
pchar = unreserved / pct-encoded / sub-delims / ":" / "#"
As you can see, the # is listed explicitly.
The segment-nz-nc set also lists the # character explicitly:
segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "#" )
So, a HTTP URI like this is totally valid:
http://example.com/#dave
Example
Here is an example Wikipedia page:
link
copy-and-paste: http://en.wikipedia.org/wiki/%22#%22_%28album%29
As you can see, the ", (, and ) characters are percent-encoded, but the # and the _ is used directly.
Can you use the #-symbol in a URL? - Yes, you can!
Note that that #-character, hexadecimal value 40, decimal value 64, is a reserved characters for URI's. It's usage is for things like email-addresses in mailto:URI's, for example mailto:username#somewhere.foo and for passing username and password information on a URI (which is a bad idea, but possible): http://username:password#somewhere.foo
If you want a URL that has an #-symbol in a path you need to encode it, with so called "URL-encoding". For example like this: http://somewhere.foo/profile/username%40somewhere.foo
All modern browsers will display this as http://somewhere.foo/profile/username#somewhere.foo, and will convert any typed in #-sign to %40, so it's easy to use.
Many web-frameworks will also help you either automatically, or with helper-functions, to convert to and from URL-encoded URL's.
So, in summary: Yes, you can use the #-symbol in a URL, but you have to make sure it's encoded, as you can't use the #-character.
In the RFC the following characters:
* ' ( ) ; : # & = + $ , / ? % # [ ]
are reserved and:
The purpose of reserved characters is to provide a set of delimiting
characters that are distinguishable from other data within a URI.
So it is not recommended to use these characters without encoding.
Basicaly no.
# is a reserved character and should only be used for its intended purpose.
See: http://perishablepress.com/stop-using-unsafe-characters-in-urls/ and http://www.ietf.org/rfc/rfc3986.txt
It can be used encoded, but I don't think that is what you were asking.
Apparently modern browsers will handle this. However you asked if this was safe and according to the spec of the RFC you should not be using it (unencoded) unless it is for its intended purpose.
I found this question when I tried to search site:typescriptlang.org #ts-ignore at Chrome, and then got the result of This page isn't working, ts-ignore is currently unable to handle this request and I saw the URL became "http://site:typescriptlang.org%20#ts-ignore/". I felt so refused, then searched # symbol's function at an URL and then I found my answer on Wikipedia.
The full format of the URL is scheme://userInfo#host:port/path?query#fragment. so when we search site:typescriptlang.org #ts-ignore, the browser will think you want to visit "http://site:typescriptlang.org%20#ts-ignore/". In this URL, http is a scheme, site:typescriptlang.org%20 is a userInfo ("%20" is escaped by a space character), "ts-ignore/" is a host. Of course, we can't visit the host named "ts-ignore" without a domain.
So, # symbol can be a separator between userInfo and host.
I have an MVC web application. The URL for a particular area is coming in as:
http://localhost/General/Bpa%3fapplication%3dTrf%23/GeneralInputs
This causes a "The resource cannot be found." error. However, if I change the URL to
http://localhost/General/Bpa?application=Trf#/GeneralInputs
then everything works. I can see from using some route debugging tricks that the controller in the first case is: "Bpa?application=Trf#", whereas the second one is: "Bpa", which is correct. How can I account for this or substitute for the encoded characters?
The encoding of the first URL is wrong. If you look at RFC 3986 you will find in 2.4 the paragraph
When a URI is dereferenced, the components and subcomponents
significant to the scheme-specific dereferencing process (if any)
must be parsed and separated before the percent-encoded octets within
those components can be safely decoded, as otherwise the data may be
mistaken for component delimiters.
That means the URL is decomposed by unencoded characters (in this case the ? matters). If the encoded string #3f is used, then the framework would have to look for a controller named "Bpa?application=Trf#" and not "Bpa". Thus a 404 / resource not found is returned.
You should not fix it on the server side; you will have to change the place where the wrong url http://localhost/General/Bpa%3fapplication%3dTrf%23/GeneralInputs is generated.
You're going to want to use this on your url:
string fixedUrl = System.Uri.UnescapeDataString(yourUrlHere);
Hope that works out for you!
I know you can apply a wildcard in the route attribute to allow / such as date input for example:
[Route("orders/{*orderdate}")]
The problem with wildcard is only applicable to the last paramter in URI. How do I solve the issue if want to have the following URI:
[Route("orders/{orderdate}/customers")]
Update:
I know there are few options to solve the issue by refactoring the code so please do not offer a solution something like:
change the route template to [Route("orders/customers/{orderdate}")]
change the date to a different format (e.g. "dd-mm-yyyy")
#bet.. I think the genericUriParserOptions is no longer applicable to .net 4.5 or later..
Also as suggested by #JotaBe, you might need to correctly decode the url request. In most case the %2F will be automatically translated to a slash '/'. So if you need to escape it you will need to decode the '%' char in the first place.. so your URL: will look something like: www.domain.com/api/orders/23%252F06%252F2015/customers
Notice the characters '%252F' will be translated to the actual '%2F'
EDIT
Ok here is the complete solution (Tried it and working for me):
Assuming you have an API endpoint like so:
[Route("orders/{date}/customers")]
public HttpResponseMessage Get(string date)
{
}
In the web.config you will need to set the requestPathInvalidCharacters to empty which tells the asp.net to allow all request
<system.web>
<httpRuntime targetFramework="4.5" requestPathInvalidCharacters=""/>
</system.web>
<system.webServer>
<security>
<requestFiltering allowDoubleEscaping="true" />
</security>
</system.webServer>
When the client sending the request to the API you will need to make sure to escape the '%' like so:
www.domain.com/api/orders/23%252F06%252F2015/customers
You then need to decode the request
[Route("orders/{date}/customers")]
public HttpResponseMessage Get(string date)
{
DateTime actualDate = DateTime.Parse(System.Net.WebUtility.UrlDecode(date)); // date is 23/06/2015
}
As noted in the comment by #AlexeiLevenkov, this is wrong:
You cannot have a parameter in the URL which accepts forward slashes, because this is a special symbol which separates each URL fragment. So, whenever you include this symbol in your URL, there will be new fragments, and a single parameter can't include several fragments.
If you want more details, read this, but these are the most relevant excerpts:
the URL path finishes in the first ? or # found in the URL. So, the slashes only create fragments in the section of the URL path before the occurrence or one of those symbols.
From section 3.4: 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.
So, the query string can include forward slashes, /, if desired, and they will not define path segments at all.
These are some solutions for the question:
include fragments for day, month and year, like this: [Route("orders/{month}/{day}/{year}/customers")] and then create the date on the server side
require the user to use a different separator, like dash or dot, which won't create problems, receive it at string an parse it yourself (or use your own custom binder to support that format)
use the URL Rewrite extension to change the URL before it reaches the routing system, and parse it as explained in the previous solution (this requires hosting in IIS)
receive it as a query string, i.e. something like this: ´?date=02/03/2015´ (you'd better encode it)
NOTE: your original question said "query string", and my comment about encoding referred to the query string, which is the last segment of an URL after the question mark, if present, like &id=27. I corrected your question so that it doesn't mention "query string", which was not the right name for what you need
C# has its own method who skips the rules of escape sequences
the name of method is
Uri.UnescapeDataString(your querystring parameter)
you can use it while getting the parameters value
You can use the following URI [Route("orders/{DD:int}/{MM:int}/{YY:int}}/customers")]
and then use a custom model binder to take DD/MM/YY and turn them into a date that you can bind in your action method.
You can choose how you want to deal with constraints (go stricter with regex's) or use validation and return 400 if it doesn't match.
The simpler approach is, to take the Day/Month/Year and put it together in code.
Here is a link for dealing with modelbinding.
I have a route in controller that should match everything in part of url and put it into string parameter.
What I have is:
[Route("api/proxy/{proxyId}/{*parameter}")]
public Task<HttpResponseMessage> Mediate(int proxyId, string parameter)
and for an unknown url, for example:
http://localhost/api/proxy/1/test?a=1&b=2
I would like "parameter" variable to contain:
test?a=1&b=2
Instead, it contains:
test
How can I specify route to not cut everything after question mark?
For this particular case I can extract it from Request.RequestUri object, but it would be.. inelegant.
You cannot do that. By definition the URL segments doesn't include the query string.
However, you can do something really easy: inside your WebApi controller you have the Request property which contains the Query String:
Request.RequestUri.Query
You simply have to concatenate the url param with this to have what you need. This includes the leading question mark:
The Query property contains any query information included in the URI. Query information is separated from the path information by a question mark (?) and continues to the end of the URI. The query information returned includes the leading question mark.
from Uri.Query Property
If you still want to force it to work in a different way, you'd need to include your own custom route provider, implementeing your own IDirectRouteProvider and registering it. See this: get a list of attribute route templates asp.net webapi 2.2
But doing something like this is unnatural. Why do things exactly in a different way as the standard way that all other people aunderstand and use?
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.