IE9 removes # part from URL (works on Firefox! ) - asp.net-mvc

I am working on an application with ASP.NET MVC Routing + AngularJS routing.
My URL lookslike:
https://example.com/Request/#/Search/Request/123
when I breakdown this (http://example.com/Request) is handled by ASP.NET MVC routing. i.e. (Area = Request, controller = "Default", action = "Index")
(#/Search/Request/123) is handled by AngularJS routing.
This works perfectly when I am on http://localhost:8080/
The issue is when I deploy this application to https://example.com/
In this case, If user clicks on above link (received via email),IE 9 recognizes only (https://example.com/Request/") and the server never gets (#/Search/Request/123).
We have enterprise SSO implemented on web server. SSO client intercepts http request and uses URL to redirect back to requested page after authentication.
if # fragment is not sent as part of http request url, sso is not able to redirect back to same page.
I believe this to be a common scenario/issue. I would keep changing the URL scheme as last resort. e.g. (# to !).
How to solve this?

Just found a blog that dealt with this issue exactly:
http://codetunnel.io/how-to-persist-url-hash-fragments-across-a-login-redirect/
He offers two ideas:
When the page loads there simply needs to be some JavaScript that accesses the hash fragment and appends it to the redirect URL in the hidden field. Here's an example using JQuery for simplicity
$(function () {
var $redirect = $('[name="redirect"]');
$redirect.val($redirect.val() + window.location.hash);
});
Or, alternatively
Instead of appending the hash fragment to the hidden field value, you could avoid sending it to the server at all and simply append it to the form action URL.
$(function () {
var $loginForm = $('#loginForm');
var actionUrl = $loginForm.attr('action');
$loginForm.attr('action', actionUrl + window.location.hash);
});

Fragments (the part of the URL after the #) are not necessarily sent to the server-side by the browser. They are for client-side usage only (navigating to a specific location in the document, JavaScript support).
RFC 2396 section 4.1:
When a URI reference is used to perform a retrieval action on the
identified resource, the optional fragment identifier, separated from
the URI by a crosshatch ("#") character, consists of additional
reference information to be interpreted by the user agent after the
retrieval action has been successfully completed. As such, it is not
part of a URI, but is often used in conjunction with a URI.
(emphasis added)
Therefore, the URL scheme you came up with will not work reliably unless you change the # to another character. Alternatively, you could use JavaScript to transfer the information from the fragment in an input that will be reliably passed back to the server. But do note that solution will only work if JavaScript is enabled in the browser, so it is (also) not a 100% reliable solution that will work with all clients.
Either way, using a URL without a fragment is a more reliable approach and IMO a better design choice if you expect that part to be interpreted by the server.

I would remove ugly URL's from your application all together.
This article will walk you through removing ugly URL's in a asp.net-mvc project. It will also ensure that you have your RouteConfig.cs setup correctly.
http://www.codeproject.com/Articles/806500/Getting-started-with-AngularJS-and-ASP-NET-MVC-P

Related

Web page without real files corresponding to URLs?

geniuses!
I need to make a demo page acting like DBpedia (http://dbpedia.org).
Two pages from different URLs,
http://dbpedia.org/page/Barack_Obama and
http://dbpedia.org/page/Lionel_Messi,
show different content.
I cannot really think DBpedia has million pages for all individual entities (E.g., Barack Obama and Lionel Messi).
How can I handle such URL request?
I know a bit about GET request but example URLs above do not seem like to use GET method.
Thank you in advance!
ps. Please teach me the process. Something like:
1. A user enters URL on a browser.
2. ...
When visiting http://dbpedia.org/page/Barack_Obama, your browser does send a GET request, e.g.:
GET /page/Barack_Obama HTTP/1.1
Host: dbpedia.org
The server (dbpedia.org) receives this GET request and then decides what to do. From the outside, you can’t know (for sure) how the server does something. The two common cases are:
Static web page: a file gets served that exists somewhere on the server. The URL path is often mapped to the server’s file system, but that’s not necessarily the case.
Dynamic web page: a file gets served that is generated on the fly. The content often comes from a database, but that’s not necessarily the case.
After trying some solutions, I'm now using Spring Web MVC framework.
Maybe Dynamic web page solution mentioned in unor's answer.
#Controller
public class SimpleDisplayController {
#RequestMapping("/page/{symbolicName:[!-z]+}")
public String displayEntity(HttpServletRequest hsr, Model model) {
String reqPath = (String) hsr.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
String entityLb = reqPath.substring(reqPath.lastIndexOf("/"));
model.addAttribute("label", entityLb);
return "entity";
}
}
I could get request using regex as you can see at the 4th line: #RequestMapping("/page/{symbolicName:[!-z]+}").
The function above returns the string 'entity' which is the name of a HTML file serving as a template.
The following code is a body part of the example HTML template.
<body>
<p th:text="'About entity ' + ${label} + '...'" />
</body>
Since I add an attribute with the key 'label' in the controller above, the template can process ${label}.
In the example HTML template, th:text is a snytax of Thymeleaf (Java library to make an XML/XHTML/HTML5 template) which is supported by Spring.

Match full url in backbone

I'm looking for solution to invoke backbone action for particular route in my app.
I know that it's possible to match url like:
localhost:3000/#posts/1
But what if I need to match url like:
localhost:3000/posts/1
Opt-in to the new HTML history API / pushState, e.g.:
Backbone.history.start( { pushState : true } );
Depending on your application, you may want to take other steps as well, e.g.:
Note that using real URLs requires your web server to be able to correctly render those pages, so back-end changes are required as well.
http://backbonejs.org/#History

do browsers remove # in URL automatically?

our front end guy needs to form a url containing the hash, (i.e, http://blah/#some-link.) when we hit this on the browser and inspect the http traffic using fiddler, we saw that everything after blah/ gets removed, so the request is really just http://blah/. we also confirmed this on our server eclipse debug log.
the request gets redirected to the correct login page by Spring security(because user hasn't logged in), but the url on the browser now shows:
http://blah/some-link (the hash got removed) but the url on the browser should really be http://blah/log-in.
any idea why this is? any fix or workaround? thanks in advance.
URI part after # is called a fragment:
URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
Scheme and hier-part identify the location of a document, and fragment helps the browser to identify a location inside this document.
Fragment is stripped from URI by client software before it is sent as a part of request.
From RFC3986:
the fragment identifier is not used in the scheme-specific
processing of a URI; instead, the fragment identifier is separated
from the rest of the URI prior to a dereference, and thus the
identifying information within the fragment itself is dereferenced
solely by the user agent, regardless of the URI scheme. Although
this separate handling is often perceived to be a loss of
information, particularly for accurate redirection of references as
resources move over time, it also serves to prevent information
providers from denying reference authors the right to refer to
information within a resource selectively.
Content after the # is only used on the client side, per HTTP specification. If you require that information on the server, you can either use a different separator, or you can submit it via ajax after the page has loaded by reading it on the client with javascript.
The part of the URI including and after the hash (#) is never sent to the server as part of the HTTP request.
The reason is that the hash identifier was originally designed to point at references within the given web page and not to new resources on the server.
If you want to get the hash identifier, you'll have to use some client-side JavaScript to grab the value and submit it with the form.
Hashmark is removed from URL when the back button is clicked in IE9, IE10 or IE11
In IE10 , first time on clicking the HREF link leads to the correct below url:
http://www.example.com/yy/zz/ff/paul.html#20007_14
If back button is clicked again the, then it comes to the below url:
http://www.example.com/yy/zz/ff/paul.html
Solution :
Please change the url with https
It works for me
you can do this with javascript
<script>
if(window.location.hash) {
console.log(window.location.hash);
window.location.hash = window.location.hash;
}
</script>

URL encoded params handling with ASP.NET MVC

My MVC web application generates an activation link that can include any character (%,+,/,etc.). I URL encode the string and generate link:
new UrlHelper(HttpContext.Current.Request.RequestContext)
.RouteUrl("AccountActivation",
new { id = HttpContext.Current.Server.UrlEncode(activationString) };
then add the domain and it looks like:
http://localhost/AccountActivation/asdlkj223%25asd%2Basw3fgasdme
The URL is then passed to the user.
The route in this case is:
routes.MapRoute(
"ActivateAccount",
"AccountActivation/{id}",
new { controller = "Account", action = "Activate", id = ""});
It seem fine to me, but the ASP.NET development server and IIS give me HTTP Error 400 - Bad request. Which means there's a problem with the URL that I can't see.
When get rid of the {id} in the route description (I also tried {*id} with no success):
routes.MapRoute(
"ActivateAccount",
"AccountActivation",
new { controller = "Account", action = "Activate"});
the URLs look like:
http://AccountActivation?id=asdlkj223%25asd%2Basw3fgasdme
and they work just fine...
I though those 2 approaches do exactly the same thing. What is the difference between them? Is it the MVC engine that performs something more for me or I miss something with the URL encoding.
Try UrlPathEncode instead of UrlEncode - some characters are illegal in the path that are legal in a query string.
That said - I believe the analysis of whether a character is 'bad' is performed after path-decoding occurs; and is done by IIS. It will reject some characters because of the possibility that the URL maps to the physical file-system and therefore could allow a user access to things they really shouldn't have access to. Equally it's done to prevent requests from sending data that really shouldn't be sent.
Generally if there's operationally no benefit from having a parameter mapped as a route parameter, then don't try too hard to map it - especially in this case where the string could be anything.
By the way - if that's an encoding of binary data; you can instead consider hex-encoding it or using modified base-64 for URLs instead - which will not cause errors if mapped as a route parameter.

Get current fragment in Route, ASP.net MVC

Is there away to get the current fragment from a route that was issued via action link. This is how I am getting the action from the route.
string currentAction = requestContext.RouteData.Values["action"] as string ?? "index";
Can I do something similar to this?
string currentFragment = requestContext.RouteData.Values["Fragment"] as string ?? "";
No, you can't do anything like this. The fragment (everything that follows the # sign in an url) is never sent to the server by the browser, so the sole fact of talking about getting the url fragment server side simply doesn't make sense.
So if you have the following url: http://example.com/foo/bar?key1=value1#abc the server will never be able to fetch abc simply because the client will never send it.
As it has already been pointed out that is not possible. Document fragments (the string after the hash as you call it) are intended for the browsers only to correctly position the viewport. They have no meaning for the server and therefore are not transmitted there.
There is however a workaround you can use. Repeat the fragment as part of your url to make it accessible for the server.
Look at the permalink to the answers in this question. For instance, the link to my answer looks like this:
http://stackoverflow.com/questions
/6285833/get-current-fragment-in-route-asp-net-mvc/6286097#6286097
See how the value 6286097 is duplicated as the last route parameter. It's intentional. You can use this technique as well.
P.S. The fragment must point to an identifier in the document (id of some HTML element). At least in XHTML only identifiers work as fragments. Valid ids may not begin with a digit therefore instead of #6286097 use something like #answer-6286097.
P.S.#2. Do not use any JavaScript trickery to get around this limitation. Basic site functionality and design must work without JavaScript - don't listen to anyone who tells you otherwise. Fragments obviously belong to the basic tool box. Use JavaScript only for advanced interactivity.
I have a workaround for you, but first of all lets get more into the problem.
The strings after the hash symbol which are called Fragment values are not query parameters but they are strings to be read by the client-side (living in the browser) and the server cannot read them because they are not sent to the server by the browser.
Some authentication providers like Google and Azure send the access token as Fragment value for security reasons so that they are not transferred over the internet after they get sent as direct response from the authentication provider.
The only way you can come around that is to use javascript to convert the fragment values to query parameters by replacing the '#' with '?' and redirecting to the endpoint in your server controller.
I suppose the easiest way is to handle all that from server, meaning you get get the request in server, send a javascript code to the browser on the fly, that replaces the '#' into '?' and redirects to your second endpoint which reads the token as strong parameter.
Here how you can do it in ASP.NET Core 3.1:
[AllowAnonymous]
[HttpGet("authredirect")]
[Produces("text/html")]
public virtual ContentResult ConvertUrlFragmentToQueryParamThenRedirect()
{
return Content("<html><script>window.location.href=window.location.href.replace('#', '?').replace('authredirect', 'authparams')</script></html>", "text/html");
}
[AllowAnonymous]
[HttpGet("authparams")]
public virtual void GetAccessToken([FromQuery] string access_token)
{
// now you have your access token server side here
}
Please remember to set your redirectUrl to the correct one, in this case 'YOUR REDIRECT URL/authredirect'.

Resources