I wrote a tiny HttpHandler, which works beautifully on my machine. However, once it was deployed to our staging server, requesting it gave an 404. I usually prefer configuring HttpHandlers in web.config, but this apparently didn’t work on the server: I fixed it by creating an .ashx file containing just the reference to my HttpHandler.
The .ashx file:
<% # WebHandler class="MyNamespace.MyProject.MyHttpHandler" %>
The web.config setting:
<httpHandlers>
<add verb="GET" path="myhandler.ashx" type="MyNamespace.MyProject.MyHttpHandler"/>
</httpHandlers>
I assume the problem is caused by the server using a "special" port (888, don’t ask why) for the website. Can it be something else, what could I be missing?
Why am I seeing this behavior on the server? The HttpHandler runs fine on my local machine with configuration just in web.config, and here it’s also served from a “random” port, i.e. http://localhost:61229/myhandler.ashx.
It sure sounds like the web.config setting is not being found.
Is this IIS 7 by any chance? In that case make sure you're putting the handler in the <system.webServer> and its <handlers> section.
If you are using IIS7 but still want to keep your old IIS 6 config files.
By setting the Application pool to run in "Classic" mode, the handler will work again.
Not recommended, but sometimes this is a quick and good enough fix.
Related
I have taken over the maintenance of a production website at a new job that is written in ASP.NET 4 Webforms and that runs on IIS 6 on Windows Server 2003. I am not familiar with Webforms nor managing IIS...so I am kind of working things out as I go here.
I have done several deployments to our production server which have worked fine, but am now setting up a test environment that is identical, just a different IP address/domain, so we can properly test changes first.
I have a problem where on this test site any URL that does NOT end with a reference to a file (always .aspx on this site) will return a 403 error on this server. For example http://users.test.oursite.com/admin will always return a 403 error when logged into the site. It should be redirecting to http://users.test.oursite.com/admin/organisation.aspx. Having an MVC background I am not even sure how this happens...but it does in production.
Browsing links within the site is fine as they always reference an .aspx file. Manually typing URLS that reference an .aspx file is fine, just not when the URL does not contain a file. This is not a problem on the production server.
As I said, I am not familiar with WebForms or managing IIS itself...so I have kind of run out of places to look.
Is there anything that comes to mind that I should be looking at that could be causing this problem?
In WebForms typically there is no routing involved.
You need to either provide a full path on the URL ending with .aspx OR
setup default documents for your website. (Index.aspx, Default.aspx etc.)
http://www.iis.net/configreference/system.webserver/defaultdocument
OR
<configuration>
<system.webServer>
<defaultDocument enabled="true">
<files>
<add value="home.html" />
</files>
</defaultDocument>
</system.webServer>
</configuration>
Default documents can be setup in IIS Properties or via web.config.
Otherwise you need to provide the full path.
And because you haven't setup the DirectoryBrowsing (in IIS), you get a 403 Error when you try to access the Directory.
Enable the Directory Browsing option in IIS (not recommended) if you want this error to go away.
I've created an httpModule to handle URL remappings, and it works great on my test system. A request for www.mydomain.com/Some_Fancy_URL gets rewritten to www.mydomain.com/some.aspx?fancy=23 and so on.
When I deploy to the actual web site, I'm getting the default IIS 404 page though.
After doing some research online, it would seem that I need to setup "Wildcard Mapping" in IIS 6 to get the request past IIS and in to my httpModule. The problem is that the site is hosted on a shared server, so it may not be possible to get the ISP to make that change.
My question is, can't I use an httpHandler to tell IIS how I want these requests handled? For example:
<httpHandlers>
<add path="*.aspx" verb="GET,POST" type="System.Web.UI.PageHandlerFactory" validate="false"/>
</httpHandlers>
It would seem like adding this to my Web.Config should tell IIS to stop validating the existence of .aspx files, and just pass the request along for me to process. It doesn't work though.
Any suggestions?
The problem with IIS 6 and ASP.NET is that they're aren't integrated. IIS needs to be told about ASP.NET via script mappings (.aspx, .asmx, wildcard and so on).
None of your web.config configuration settings will influence IIS because web.config is there to configure ASP.NET's behaviour, not IIS. IIS has no knowledge of web.config.
Unless you can hand off a request to the ASP.NET pipeline (via a script map) nothing will happen and all your web.config settings will be ignored.
With IIS 7 the story is quite different. In IIS7, ASP.NET and IIS are closely integrated and share the same pipeline thus permitting you to achieve the result you're looking for.
The alternative may be to find out if your hoster runs a URL rewriter such as ISAPI_Rewrite on their servers. That way you could rewrite urls without having to map a wildcard scriptmap to IIS6.
Through some trial and error, along with more web searches, I found a solution. It essentially parallels Kev's answer.
IIS won't treat a request as .NET unless it has a known file extension (.aspx, .ascx, etc.). When I send along something like www.mydomain.com/anything it looks for a file or folder named "anything", and when it doesn't find one, it just drops off to the default IIS 404 handler.
That's where I took over. I changed IIS 6 to forward 404 problems to /404.aspx. I then created that page with a generic "Your file wasn't found" message in the same style as my web site.
Here's the good part: Now that IIS is sending 404's to a .NET page, the custom httpModule I created is getting fired. The request is for 404.aspx, but IIS is nice enough to also append the original URL as well. You get something like:
www.mydomain.com/404.aspx?404;http://www.mydomain.com/anything
This allows me to parse the request in the httpModule, and rewrite as needed!
I've used the UrlRewriting.Net module for a couple years now without any problems in Windows XP and Windows 2003. I just recently upgraded my home PC to Windows 7 and started developing a new website.
The plan was to use .html extensions and rewrite them to their .aspx counterparts using the UrlRewriting.Net module. Everything works flawlessly in VWD 2008, but when I try running it through IIS7 it is a different story.
When I try to access a page via the .html rewrite I can no longer access Page.User; it keeps returning null. If I hit the page using it's .aspx extension, Page.User is correctly populated. I should also mention that I have a LoginView controller in my Master Page and it suffers from the same symptoms: When accessing via .html extension it shows the AnonyousTemplate; When using .aspx extension it properly shows the LoggedInTemplate. I'm guessing the two are related.
[Note: I've also tried extensionless URLs and they exhibit the same problem]
The only way I've gotten it to work is to switch the application pool to Classic, which then requires me to add an ASP.Net ddl handler for the .html extension [otherwise it is handled by the StaticFileHandler and comes up as a 404 error]. However, I'd like my web app to run properly for people without having to fiddle around with IIS.
So I am left with several questions:
Does anyone have ideas as to why Page.User always equals null for .html => .aspx rewritten pages?
Why does it work in VWD 2008, but not IIS7?
What changed from IIS6 => IIS7 that could have caused this?
Any other thoughts on workarounds?
[Note: I just tried a .aspx => .aspx rewrite and it did not exhibit the problem. Not really what I want, but thought I should mention it.]
Just had a breakthrough with the UrlRewriting.Net module. This makes it work in Integrated Mode in IIS7:
<modules runAllManagedModulesForAllRequests="true">
After figuring it out I did a search on "runAllManagedModulesForAllRequests" and the first thing that popped up was Scott Guthrie's blog which actually talks about using it for this purpose.
Another approach that seems to work is to remove the Session module and readd it leaving the "Invoke only for requests to ASP.NET applications or managed handlers" checkbox unchecked. It looks like this in the web.config file:
<system.webServer>
<modules>
<remove name="Session" />
<add name="SessionManualAdd" type="System.Web.SessionState.SessionStateModule, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</modules>
</system.webServer>
It seems the problem is that the Session module doesn't execute for say '*.htm' files when HttpContext.RewritePath is used, but removing and readding the module in this fashion causes the Session handler to be executed for the request.
This solution was suggested on the thread below. Unfortunately Microsoft chose not to explain the reasoning behind this behavior fully:
http://connect.microsoft.com/VisualStudio/feedback/details/357248/context-rewritepath-disables-session-module-in-iis7
Microsoft included a fix for this issue (at least for extensionless urls) in Service Pack 1 for Win7 and Windows Server 2008 R2:
http://www.microsoft.com/download/en/details.aspx?id=5842
Also available as a hotfix: http://support.microsoft.com/kb/980368
After this patch is applied, ASP.NET 4 applications can handle requests for extensionless URLs. Therefore, managed HttpModules that run prior to handler execution will run. In some cases, the HttpModules can return errors for extensionless URLs. For example, an HttpModule that was written to expect only .aspx requests may now return errors when it tries to access the HttpContext.Session property.
After applying SP1 or the hotfix, no web.config changes are needed to make the session and forms auth work for extensionless URLs rewritten to asp.net pages/handlers/etc.
I don't know if this fixes anything for rewrites to static file extensions like .htm. My guess is, probably not. I would try to avoid setting runAllManagedModulesForAllRequests="true" in production environments, because it adds unnecessary overhead on static file requests.
I have a customer of ours that sent out a publication referring to my site but they used the wrong address...they did not provide a page name...it looks like this:
mywebsite.org/Resources/toolkits/bridging
when it should have been
mywebsite.org/Resources/toolkits/bridging/default.aspx
Is there a way to tell ASP.NET to default to this default.aspx when it sees this kind of request or even better, have IIS 7 handle this easily?
This site is live so I would like to avoid having to introduce code if possible.
As per other suggestions, this should be done in the IIS configuration for your website using the IIS Admin tool.
There is however, another alternative - you can add a section in the web.config of your actual ASP.NET application, allowing you to override the IIS configuration right from your application:
<system.webServer>
<defaultDocument>
<files>
<clear />
<!-- Specify each of your files by order of preference here -->
<add value="Default.aspx" />
<add value="Index.aspx" />
<add value="MyOtherPage.aspx" />
</files>
</defaultDocument>
</system.webServer>
The caveat to this though is it may be a little obtuse when the IIS administrator can't figure out why the server configuration isn't working the way he's got it configured. It's not always right to do something just because you can.
Finally, just in case you don't have access to the IIS server or your IIS administrator has reasons for not adding Default.aspx to the default document list in the IIS configuration and for whatever reason, you don't wish to override the IIS configuration in your web.config file, then the quickest and simplest way is to simply create a file called default.asp in that directory containing:
<% Response.Redirect("default.aspx") %>
Default.asp is in the default document list on IIS. The code will automatically redirect the call to the correct page. The downside to this approach though is that there's a performance hit - every time someone calls default.asp - directly or otherwise, the redirect needs to happen which isn't free.
In the Documents tab of the web site properties in IIS you can specify default documents. If you are using .Net2.0 or later on that machine then Default.aspx should already be set....
Default.aspx is not, oddly enough, set as the default document in an IIS installation; In IIS 7, the setting is under "HTTP Features", called "Default Document". Add default.aspx to that list and you should be OK.
If not, you'll need to add a 404 handler that redirects when it sees that URL.
We are using the Intelligencia URLRewriting module for asp.net with version 2.0 of the framework and IIS6. Our URLs typically have no extension.
I understand that IIS6 cannot really deal with this situation without a blanket wildcard (which causes other problems).
However, it works! Sometimes. At other times (e.g. on one dev's machine, and on my machine when I point a different virtual directory at the app) it doesn't. By "it doesn't work" I mean the configured HttpModules never even get hit.
Can anyone explain this?
Thanks.
So it turns out what was happening was the following:
request comes in to (say) http://website/products/productid
IIS can't find this hence we get a 404
by chance we have a custom error page set up in IIS for 404s
this error page sticks the referring URL on the end of the 404 error.aspx page
so we get a redirect coming into asp.net along the lines of:
http://website/error.aspx?404;http://website/products/productid
our URLRewriting regexes were now set up in such a way that they discarded the error.aspx bit and dealt with http://website/products/productid as if it were the actual URL
so asp.net renders http://website/product.aspx?id=productid as requested!
I guess this could prove to be a useful kludge for someone, but we're moving to an isapi filter. One heads-up is that this will by default lead to a tight loop of redirects!
If you run a site using the Visual Studio development web server all requests will be handled by asp.net so your HttpModule will run.
On IIS6 this should not happen unless it is set up to forward the requests to asp.net.
Are you sure that when "it works" you aren't running under the Cassini development web server included in VS.NET ? Because extensionless wildcards do work under Cassini, which can be very confusing to say the least.
If you are using an IIS6 with ASP.net 4.0, you must specify and register the modules like this:
<system.web>
<httpModules>
<add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter"/>
not
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter"/>
</modules>