ASP.NET Page Routing - URL Parameters stripped from target resource - c#

ASP.NET c# project... trying to do a very simple page route.
Please note that I know this is NOT actually doing any dynamic routing... I have the id hard coded like this for a reason.
Example:
RouteTable.Routes.MapPageRoute("Test", "ABC", "~/Test.aspx?id=101");
I can browse to http://www.mysite.com/ABC no problems, the page Test.aspx loads, the routing is working as expected.
BUT... where has my id=101 gone?
Request.QueryString["id"] \\ is null...
Page.RouteData.Values["id"] \\ is null...
How can I get hold of the hard coded id in my target resource for the routing?

I got it working by passing DataTokens.
In my real world scenario I don't know what the URL parameters will be (there could be just the "id" like in my question... or there could be others, sometimes none), so I have to do the following:
First check to see if there is a "?" character in the routing target... if there is, then:
Run the string after the "?" character through HttpUtility.ParseQueryString
Then, loop through that collection and add them to a System.Web.Routing.RouteValueDictionary
Then finally add the route, with the DataTokens property set to the RouteValueDictionary

Related

How to get the URL without the Query String or the Id part?

Let's say my urls are:
https://www.mywebsite.com/app/company/employees/5
https://www.mywebsite.com/app/company/employees?id=5&name=jack
https://www.mywebsite.com/app/company/employees/5?clockId=1
I'm looking for a way to get the "base" path, or whatever it's called. Like the "base" path would be "/app/company/employees" for all, without the "/5" part or "?id=5&name=jack" or "/5?clockId=1" parts.
I was using string.Join("/", context.Request.ApplicationPath, context.Request.RequestContext.RouteData.Values["controller"], context.Request.RequestContext.RouteData.Values["action"]) to get it (context is HttpContext), but it doesn't work the way I want since it includes the Index action too. Like if the Url is "https://www.mywebsite.com/app/company" I want "/app/company/" not "/app/company/Index". I can always check if the action is Index or not but it feels like kind of a "code smell" to me.
Also using context.Request.Url.AbsolutePath doesn't work either since it returns "/app/company/employees/5" (It returns the path with Id)
Looks like the only two things you need from URL are action and controller and if the action is "index" you don't need it. In this case I believe that you are doing it right. This is a slightly modified piece of code I was using in ASP.NET MVC project:
string actionName = this.ControllerContext.RouteData.Values["action"].ToString();
string controllerName = this.ControllerContext.RouteData.Values["controller"].ToString();
if (actionName.Equals("index", StringComparison.InvariantCultureIgnoreCase))
{
actionName = string.Empty;
}
string result = $"/{controllerName}/{actionName}";
There is one more thing to mention: "areas". Once I was working on website which had them, so they may appear in your URL too if your website uses "area" approach.
I hope it helps 😊

MVC 3 pass model item to #Html.ActionLink text?

How to pass model item to #Html.ActionLink text...
#Html.ActionLink( #item.GetLink(),"Controller", "Action" )
this isn't working, if i put it in " " it becomes string. Any ideas?
#Html.ActionLink(item.GetLink(), "Action", "Controller")
(without # character in first parameter, and swap action and controller)
Adding to Evgeny Levin's answer, you could also download the MvcContrib library and strongly type your ActionLinks like so
#Html.ActionLink<Controller>(x=>x.Action(), item.GetLink())
I prefer this method over magic strings, and then in my solution configurations I create a new one that mimics Debug but has the value for MvcBuildViews set to true, and then when you compile, if you have any invalid Links to controller/action pairs, it throws a compiler error. Has saved me many times of pushing out code that doesn't pass required Action parameters

Getting ASP.NET MVC to correctly escape the # (hash/pound) character in routes

I've got a route that looks like this:
routes.MapRoute(
"BlogTags",
"Blog/Tags/{tag}",
new { controller = "Blog", action = "BrowseTag", viewRss = false }
);
And I create a URL using that route like this:
<%= Html.RouteLink(Html.Encode(sortedTags[i].Tag),
new { action = "BrowseTag", tag = sortedTags[i].Tag })%>
However, when a tag with a # character (like "C#") is used, the routing engine doesn't escape it, so I get a URL that looks like this:
C#
What I need is the # escaped so that it looks like this:
C#
I tried doing a Url.Encode on the tag before it went into the route, like this:
<%= Html.RouteLink(Html.Encode(sortedTags[i].Tag),
new { action = "BrowseTag", tag = Url.Encode(sortedTags[i].Tag) })%>
But that makes the routing engine double escape the # (which causes an ASP.NET crash with a bad request error)):
C#
How can I get the routing engine to escape that # character for me correctly?
Thank you for your help in advance.
As a very bald solution, I would manually replace "#" with "%23" in the output of RouteLink. Provided you don't use fragments in your urls, it should work.
You could use regular expression to only apply replace to the last part of your url.
I have a similar SO question relating to "/". While researching that issue I learned that ASP.NET decodes the URL values before they get passed to the MVC framework, and since "#" has special meaning to URLs (just like the "/" I was dealing with) there's a good chance that something in the base routing engine is causing this behavior.
Like Levi mentioned in his comment, one solution is to use ASP.NET 4.0. Another solution would be to write a RouteLink helper that automatically replaces "#" with some marker (like "!MY_HASH_TOKEN!") and then reverse that replacement in your controller (or perhaps via a HttpModule of some sort).
Or, just throw in the towel and pass the tag value as a querystring argument. Not as sexy, but its simple and it works.

Problems with Request.QueryString. Reads cache instead of URL

I'm trying to retrieve the value of myID from my URL.
I'm testing this using <%=Request.QueryString["hotelid"] %>.
It only works the first time the page is loaded either in a new browser, or if my project has been rebuild.
My URL string is typical: http://my/path/to/site/?hotelid=2.
If I try <%=Request.QueryString %>, I'm also getting other values as well. Values I do not see inthe URL string.
What am I missing here?
Update:
Using <%=Request.RawUrl%>, I get the following results:
/Util/NotFound.aspx?404;http://localhost/en/Tjenester/Hotellguiden-2/Hotel-informasjon/?hotelid=3
I have NO idea what the /Util/NotFound.aspx?404 is or where it comes from.
My URL looks like this:
http://localhost/en/Tjenester/Hotellguiden-2/Hotel-informasjon/?hotelid=2
Update 2:
I'm currently investigating if it is EPiServer CMS that is using some kind of caching.
Update 3:
I have solved it. EPiServer is using EPnCachePolicyTimeout which isset to 1 hour. Setting this to 0 (zero) solved my problem.
Sometimes is really helps just writing aboutthe problem here, talking "aloud" about it and voila :)
You need to turn off caching or add your parameter names to the config attribute httpCacheVaryByParams or overwrite the custom caching key method and make it diff on every querystring parameter.

Response.Redirect using ~ Path

I have a method that where I want to redirect the user back to a login page located at the root of my web application.
I'm using the following code:
Response.Redirect("~/Login.aspx?ReturnPath=" + Request.Url.ToString());
This doesn't work though. My assumption was that ASP.NET would automatically resolve the URL into the correct path. Normally, I would just use
Response.Redirect("../Login.aspx?ReturnPath=" + Request.Url.ToString());
but this code is on a master page, and can be executed from any folder level. How do I get around this issue?
I think you need to drop the "~/" and replace it with just "/", I believe / is the root
STOP RIGHT THERE! :-) unless you want to hardcode your web app so that it can only be installed at the root of a web site.
"~/" is the correct thing to use, but the reason that your original code didn't work as expected is that ResolveUrl (which is used internally by Redirect) tries to first work out if the path you are passing it is an absolute URL (e.g. "**http://server/**foo/bar.htm" as opposed to "foo/bar.htm") - but unfortunately it does this by simply looking for a colon character ':' in the URL you give it. But in this case it finds a colon in the URL you give in the ReturnPath query string value, which fools it - therefore your '~/' doesn't get resolved.
The fix is that you should be URL-encoding the ReturnPath value which escapes the problematic ':' along with any other special characters.
Response.Redirect("~/Login.aspx?ReturnPath=" + Server.UrlEncode(Request.Url.ToString()));
Additionally, I recommend that you (or anyone) never use Uri.ToString - because it gives a human-readable, more "friendly" version of the URL - not a necessarily correct one (it unescapes things). Instead use Uri.AbsoluteUri - like so:
Response.Redirect("~/Login.aspx?ReturnPath=" + Server.UrlEncode(Request.Url.AbsoluteUri));
you can resolve the URL first
Response.Redirect("~/Login.aspx);
and add the parameters after it got resolved.
What about using
Response.Redirect(String.Format("http://{0}/Login.aspx?ReturnPath={1}", Request.ServerVariables["SERVER_NAME"], Request.Url.ToString()));

Categories