|
Watch out if you have a validator in any of your pages because they will request a javascript throught the WebResource.axd and if in "Application_BeginRequest" you treat this as a fake URL the page will not get its javascript but whatever you serve it..
Take care as this took me 1/2 hour to figure out ..
|
|
|
|
|
Thanks for your feedback.
Really a useful tip.
Cheers.
|
|
|
|
|
For now I just put the following line in Application_BeginRequest event handler:
if (File.Exists(Request.PhysicalPath) ||
Directory.Exists(Request.PhysicalPath) ||
Request.AppRelativeCurrentExecutionFilePath.ToLower().EndsWith(".axd"))
{
return;
}
|
|
|
|
|
Hello, great post ...
I do not know if possible, use this technique for virtual domains like as http://virtual.domain.com
Can you help me ?
|
|
|
|
|
Yes, you should be able to use this with subdomains like http://virtual.domain.com without any problem.
Same code will work for you.
Thanks for your feedback.
Manu
|
|
|
|
|
To all you guys using various string functions (IndexOf, Split, etc) to find your query strings and Url parts, stop! Just use a System.Uri and your done! It already parses everything for you. You may have to split the Query Strings, but at least it does the heavy lifting for you.
Thanks.
|
|
|
|
|
Isn't the "Custom HttpHandler" the correct (best practice) way of doing this? What advantages are in your method? Did you try HttpHandler and not get it to work? (Cuz that's what I did)
|
|
|
|
|
Hi Jasmine, Thanks for your response.
An HttpHandler will take more system resources as it will listen to more requests, while only .aspx requests will be handled by global.asax file.
Please let us know if you have additional information.
Your feedback is appreciated.
Manu Agrawal
|
|
|
|
|
That is a very good point - anything that doesn't have to go through that ASP engine, is a Good Thing. In your case, adding an HttpHandler is simply overkill - all the things you want to alter are already going through the ASP engine. Mine actually responds to all requests that aren't aspx pages, and now that I think of it, that's why I didn't use something similar to your method in the first place. I had a slightly different requirement than your site. In my case, I wanted to handle all files with my custom handler, so I had to re-map the file type *.* to be handled by the ASP engine. This means all requests to my site are going through the ASP engine. That's a clear performance problem, but it adds the ability for me write custom file handling code very easily. Your method is better, if the files you are handling are aspx files, but what would you do if you needed to serve up music, video, and various application-specific documents (like .doc, .ppt, etc)?
The reason I ask is because it took me a long time to get the HttpHandler to work correctly, and nobody out there was able to help me. I finally figured it out myself, but I was amazed at the sheer number of people who basically said to do it another way. Your method seems to be a popular alternative, and one that most people seem to use when they find out that HttpHandlers are tricky to get right.
(I'm basically building a compliance system... such that users from different companies can only get the documents that are approved by their compliance department. There is a possibility of us having multiple versions of the same document, one for each company, but we want the URLs to be the same so people can share them between companies, and everyone still sees the correct versions. We want the server to serve up the correct version based on the user's login, and we wanted to send back an error if the person is not logged in, or if the company does not have an approved version of the requested document. This had to work with all requests for the document, regardless of the actual URL used.)
|
|
|
|
|
Hi,
It's not strictly true that an HttpHandler will consume more resources - the handler will only listen to the type of resource it is written to process, so in the case of rewriting (say) *.html requests, the handler would only be invoked for those requests. One of the BIG advantages of using an HttpHandler is that we can create friendly postbacks to the page that dont contain the target scripts query strings or rewritten resource name.
Check out my article here[^] for more information on this subject.
--- Regards Steve
|
|
|
|
|
|
To all you guys using <urlMappings> and having problems with postback and/or AJAX UpdatePanel... I ran into a bug about the action of the form. It will redirect on the postback or callback to the redirected URL instead of the original URL. The next piece of code will fix this:
private void FixUrlMapping()
{
string clientFilePath = Request.RawUrl;
int index = clientFilePath.IndexOf('?');
if (index >= 0)
clientFilePath = clientFilePath.Substring(0, index);
if (clientFilePath != Request.CurrentExecutionFilePath)
{
// This request is done using a mapped URL. This has set the action of the html-form (<form action=...>) back
// to the physical aspx file. This results in a navigation problem navigating away from the mapped url to
// the physical url.
// For example: whithout this code, a postback from /Quote/MyQuotes.aspx would result in the URL /Order/MyOrders.aspx?Type=Quotes
// This is not a problem for the actual order/quote page, but the navigation will point to Order/MyOrders.aspx.
// Thus the crumbtrail, menu and URL are misleading.
// Fix: Change the 'action' of the form back to the virtual admin page
string action = clientFilePath;
index = action.LastIndexOf('/');
if (index >= 0)
action = action.Substring(index + 1, action.Length - index - 1);
string script = string.Format("theForm.action='{0}';", action);
Page.ClientScript.RegisterClientScriptBlock(typeof(string), "ResetAction", script, true);
// Bugfix for UpdatePanels. The call-back would reset the action of the form.
script += string.Format("theForm._initialAction='{0}';", action);
ScriptManager.RegisterClientScriptBlock(Page, typeof(string), "ResetAction", script, true);
}
}
Marco Vervoort - Pulse Business Solutions
|
|
|
|
|
Hi;
Though your post does not relate to this article in particular, still it is good and thanks for that.
This article is about NOT having to use <urlmappings> in the Web.Config; It explains how to map URLs that physically do not exist (where contents come from a database).
Thanks again for your interest.
|
|
|
|
|
Thanks, I figured out the rest, but was unable to figure out how to enable postbacks on the virtual URLs.. thanks it worked so easily.
|
|
|
|
|
Yeah, I like the idea. I actually really like how Ruby on Rails let's you have friendly url's in the form of:
mysite.com/<view>/<action>/id=<id>
e.g. mysite.com/clients/edit?id=3.
Note there is no <page>.aspx in the requested url! Can you tell me if one can do a similar thing in asp.net + IIS?
Thanks,
Ben
|
|
|
|
|
Hi, thanks for your feedback; Yes I have also done this extension less URLs in PHP.
It is possible in ASP.NET by writing a custom http handler in IIS or by directing IIS to forward ALL incoming http requests to ASP.NET engine.
I am still open to any suggestions, if this can be done without tempering with IIS.
Thanks again!
Manu Agrawal
|
|
|
|
|
IN II7 via web config - I read the article online the other day - dont remember where though.
|
|
|
|
|
|
One of your requirements that you mentioned ("The virtual URLs requsted by the user may or may not have file extensions.") is something I've researched in the past too.
The problem, as I understand it, is that when your application is running under VS.NET, everything is tickety-boo. You request a URL like /finance/loan, the development web server passes this to ASP.NET, at which point you catch it in global.asax, you see the file doesnt exist and serve something else, perhaps from a database, instead.
However, when you run the same code under IIS, aspnet_isapi.dll is only invoked for file extensions that are mapped in the IIS configuration. Basically, your code is never called because "/finance/loan" is not recognised by IIS as a request that needs ASP.NET.
I've just tested your code and my suspicions were right:
In the VS.NET development web server:
http://localhost:1968/URLMapping/finance/loan works perfectly;
Under IIS:
http://localhost/urlmapping/finance/loan gives a standard 404.
We can make your code work in IIS:
http://localhost/urlmapping/finance/loan.aspx
but only by adding .aspx to the end, as this invokes ASP.NET before IIS realises the file doesnt exist.
Annoying, but it seems ISAPI is the only way to catch these kind of requests without big configuration changes. Anybody got this working well with "free" code?
Thanks
PB
|
|
|
|
|
Thanks PB.
I am sorry that it works only with files with extensions. I will need to spend more time on it.
In the meantime I have edited the article description that it only supports files with extensions.
If anybody finds a solution for extension-less files, please do post here.
Thanks.
Manu Agrawal
|
|
|
|
|
The only solution is in the actual IIS configuration - there's no way you can write code to capture requests to extension-less files, as IIS will simply not pass the request on to your code in the first place.
While you can workaround this by configuring IIS to pass all page requests to the ASP.Net engine, this is only useful to those hosting in-house - there's no shared hosting service I know of which will give you this level of control over their servers.
|
|
|
|
|
If the file does not exits you fall back to 404
You can create a custom 404 page, say error404.aspx and then you can rewrite path for that 404 aspx page.
I have not tested, but theoretically there's no reason it should not work.
|
|
|
|
|
I have also seen someone use an alternative approach before where you create a Sales directory/folder and place a default.aspx page inside it. Configure IIS to use a default document name of default.aspx. Then when a request for something like http://localhost/website/Sales/123 comes in, the code for the default.aspx fires where you can then pick up the requested url/sales id and present that.
|
|
|
|
|
I eventually did it (by injecting some code into global.asax.cs)
http://www.linkibol.com/linkibolcu/volkan[^]
http://www.linkibol.com/linkibolcu/volkan/etiket/web20[^]
http://www.linkibol.com/linkibolcu/etiket/web20[^]
(The system even works for native Turkish custom urls like /etiket/girişimcilik)
Here is a snippet for the interested:
protected void Application_BeginRequest(object sender, EventArgs e)
{
if(Request.Url.ToString().ToLower().IndexOf("error404")>-1&&Request.Url.ToString().ToLower().IndexOf("favicon.ico")==-1)
{
MapPath(
Converter.QueryStringToTRDoubleByte(
Request.Url.Query.ToString()
)
);
}
}
Where the MapPath simply uses
HttpContext.Current.RewritePath("/Default.aspx?"+theQueryString);
after some logic switches and filtering to achieve the effect.
p.s.
Nothing special about Converter. It is my custom conversion object.
HTH,
|
|
|
|
|