IRouteHandler in Web Forms: Routing requests that require HttpContext.User - c#

I'm trying to add a pretty basic route to an Asp.Net Web Forms app (running under IIS 7, integrated mode): for requests coming to http://mydomain.com/foo/ I would like to show the results of a dynamic page (http://mydomain.com/foopage.aspx).
I've created a RouteHandler that does all this and it seems to be routing correctly.
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var page = System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath("~/foo.aspx", typeof(MyApp.Web.Foo)) as MyApp.Web.Foo;
return page as IHttpHandler;
}
The problem is, inside my RouteHandler's GetHttpHandler method, all the instances of the current user (requestContext.HttpContext.User, System.Web.HttpContext.Current.User) are null. Sadly, foo.aspx needs to know what the current user is (for login controls, role stuff, etc), so rendering the page is throwing null reference exceptions. My guess is that these route handlers are firing off before Asp.Net gets the chance to wire up the HttpContext with user info. Any idea of a work-around?
PS - I realize this can be accomplished by doing a Server.Transfer in a page at http://mydomain.com/foo/default.aspx. I'd like to use routing for this sort of thing rather than having a bunch of useless folders cluttering things up.
Thanks!

See the answer to this question, very similar.

I managed to figure this one out myself.
Much like this question, my routes were working just fine when the route origin ended in .aspx (http://mydomain.com/foo-origin.aspx), but failed when they did not (http://mydomain.com/foo-origin/).
The MSDN article on setting up routing with web forms tells you to make a few changes to web config, but leaves out that you need to set runAllManagedModulesForAllRequests to true in the modules node:
<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
</system.webServer>
</configuration>
Now it works swimmingly.

Related

ASP.NET MVC site always redirects to log-in page

This has got me baffled! I've just created a new site using identity framework 2, and it all works fine except that it always shows me the login page. I've spent some time looking at possible answers on the Internet, so let's eliminate some possibilities.
On my home controller, I haven't got an [Authorize] dressing - and just for good measure, I stuck on [AllowAnonymous] to check this didn't help:
I don't think I've got any filters which are applying authorisation to all pages:
Here is part of my web.config:
The strange thing was that when I first created the site, it worked. I then dressed the home controller with the [Authorize] attribute, which forced me to log in. That all worked too. It's only now that I've removed the [Authorize] attribute that things aren't working.
I'm sure I'm being a bozo, but can't work out why. I've rebuilt my solution, exited and re-entered Visual Studio 2015, etc. I'm using MVC 5 and entity framework 6.
Thanks in advance!
The web config should overwrite the IIS express config but in this case it seems it does not. What you can try to do is to turn it off on the IIS level as well.
You can go to this directory \IISExpress\config\applicationhost.config open up this file and set the <windowsAuthentication enabled="false" />.

Url Rewriting ASP.NET - Some images refuse to load

I have recently implemented UrlRewriter (http://urlrewriter.net) on my website and am having some issues.
I am implementing it so the page requests are extension-less. For example, www.example.com/my-cool-product, redirects to www.example.com/Product.aspx?id=1. This works fine.
The problem I am having is that, some of my site images are refusing to be served as static content. If I put the path to some of images on my site, they are served up right away (as static content), but some images try to route through the .NET pipeline.
For example, www.example.com/Asset/Image/Image.png returns a 404 as it is trying to hit up www.example.com/Asset/Image/Default.aspx.
Can anyone shed any light on why this is happening for some images and not for others?
What version of IIS are you using? You may need:
<modules runAllManagedModulesForAllRequests="true">
In your web.config <system.webServer> block
Or set a <base> url in your page head

ASP.Net MVC returns 404 for URLs with Action parameters but not for default route

I am using a WebForms application with some MVC components added in. The idea is to move more and more of the app over to MVC but there is no way it can be transitioned all at once. For various reasons I cannot control it must use ASP.Net 2.0 and MVC 2.0 since those are what ship built-in. I must also support IIS 6 and IIS 7.
First, I am well aware of the problems with extensionless routing and I am not attempting to use it so there are no issues with wildcard mappings, etc. I first attempted to use my routes ala "{controller}.aspx/{action}/{id}" but after banging my head on the wall I switched to "{controller}.mvc/{action}/{id}" but am having the same issues.
Second, I cannot get this to work even in IIS 7 Integrated mode on my dev machine, let alone Classic mode or IIS 6. It all runs correctly under Cassini but once I deploy to IIS 7 the MVC components break. Since this is on my dev machine I know ASP.Net is registered with IIS correctly and I can see all the inherited HTTP handlers in the control panel (eg: ASPX maps to PageHandlerFactory).
Symptoms:
All ASPX WebForms requests work perfectly.
An MVC requests to just the controller with no action/id specified get routed to MVC and execute properly as well.
Any request to an MVC route with an action or id immediately returns a 404. It is as if IIS thinks the ".mvc" extension is part of the folder path so it ignores the HTTP handler and returns a 404.
In other words:
/app/WebForm.aspx - HTTP 200 OK, executes WebForm.aspx.cs code-behind
/app/Fancy.mvc - HTTP 200 OK, executes /Controllers/FancyController.cs, Index method
/app/Fancy.mvc/DoThingy - HTTP 404 NOT FOUND, even though FancyController has DoThingy method
Bad Solutions: I have tried things like setting runAllManagedModulesForAllRequests but not only is that bad for performance it also breaks my Web Forms as well. Even when I set it to ignore all routes with .ASPX in them they still break.
I cannot use wildcard mapping so that is no help.
Other Details:
I setup my HTTP Handler in web.config/system.WebServer. It is the first handler listed.
<add name="MvcRoutingHandler" preCondition="integratedMode" verb="*" path="*.mvc" type="System.Web.Routing.UrlRoutingHandler, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" resourceType="Unspecified" />
It doesn't seem to matter what handler I specify or what options - IIS just doesn't seem to be examining any of this configuration (again because it seems to think the Fancy.mvc part of the path is a directory name, doesn't find that directory, then bails).
My routes:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");
routes.IgnoreRoute("{resource}.asmx/{*pathInfo}");
routes.IgnoreRoute("{resource}.aspq/{*pathInfo}");
routes.IgnoreRoute("{resource}.svc/{*pathInfo}");
routes.MapRoute("Default",
"{controller}.mvc/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
Update: I tried using IIS 7 Classic mode; I then added a .mvc mapping in the IIS Manager pointing at the asp_net ISAPI dll and got the same result
OK just so others don't look foolish, it turns out that this was a problem with URLs... the URL was being sent to the root of the site, not the app directory. I should have checked that to begin with. I didn't think this was the problem because when I manually typed the URL into the address bar it worked on the Index but the action method required HttpPost, so it was a combination of factors that made the script and manually-entered addresses spit out the same error message.
For anyone else mixing WebForms and MVC, double and triple-check that your URLs are correct. Here is some code I am now using on the WebForms master page so my client-side JS can know where to route MVC requests:
string baseUrl = Request.Url.GetLeftPart(UriPartial.Authority);
if (baseUrl.EndsWith("/")) baseUrl = baseUrl.Substring(0, baseUrl.Length - 1);
baseUrl = baseUrl + ResolveUrl("~/");
Page.ClientScript.RegisterHiddenField("BaseUrl", baseUrl);

Restfull urls for ASP.NET page on IIS

Ok I had a huge Issue giving this a proper title, my excuses for that.
Anyways I have started slowly to look at Web and ASP.NET again, I am a C# developer but I have mostly worked with Windows applications the past 5 years or so, It is not that I haven't touched the web as such in that time, but this is as web services (Restfull as well as the ugly SOAP services) I have also worked with more "raw" web requests.
But I have not worked with IIS or ASP.NET in all that time.
What I would like to do is hos a web page that uses a URL style I could best describe with "like rest", hence the "Restfull urls" title. Because I think most people thinks of such URL's in terms of:
http://example.com/item/
http://example.com/item/23/
and so forth. Not that they have to look like that, however I would like to use such URL's instead of
http://example.com/item?id=23
I know subtext does this, but i have not had any luck finding it in their code base.
Now as far as I can tell I could just implement some IHttpHandler's, but at least for the examples I have seen of that, they write the page source back in code, and I still have master pages etc. I wish to use instead of taking over all that stuff my self, I really just kinda wants to route http://example.com/item/23/ to http://example.com/item and asking for the item with id 23...
I hope this makes sense at all >.<... And that someone has some better examples at hand that what I have been able to find.
You can achieve this using Routing here is a link to an MSDN blog, The .Net Endpoint - Using Routes to Compose WCF WebHttp Services that should get you started.
If you're looking at asp.net/IIS, another option to look at is ASP.Net MVC. It's pretty straight forward to create RESTful services.
Here's a tutorial:
http://www.codeproject.com/Articles/233572/Build-truly-RESTful-API-and-website-using-same-ASP
So here are your options-
For .net 3.5 sp1 framework with IIS7 you can use asp.net routing feature to have MVC style urls that you mentioned should create a custom route handler implementing IRouteHandler interface as explained here How to: Use Routing with Web Forms and register your route rules in Application_Start method in Global.asax. For your example you can register a route like this
routes.Add("ItemRoute", new Route
(
"item/{itemId}",
new CustomRouteHandler("~/item.aspx")
));
and then you can access itemId in your routed item.aspx page by checking request context item
requestContext.HttpContext.Items["itemId"]
For .net framework 4 MVC you dont have to create a custom handler, you can directly use
routes.MapPageRoute("ItemRoute", "item/{itemId}", "~/item.aspx");
in you global.asax Application_Start method.
This link explains more about the Routing
A way of achieve this is using URL rewriting.
If you're planning to host your Web application in Internet Information Services 7.x, you can take advantage of IIS URL Rewriting Module:
http://www.iis.net/download/urlrewrite
URL rewriting is just mapping a friendly URL to an unfriendly, common one, which is programming-friendly to inspect GET parameters.
For example:
http://yourdomain.com/item/48 => http://yourdomain.com/Items.aspx?Id=48

Posting forms to a 404 + HttpHandler in IIS7: why has all POST data gone missing?

OK, this might sound a bit confusing and complicated, so bear with me.
We've written a framework that allows us to define friendly URLs. If you surf to any arbitrary URL, IIS tries to display a 404 error (or, in some cases, 403;14 or 405). However, IIS is set up so that anything directed to those specific errors is sent to an .aspx file. This allows us to implement an HttpHandler to handle the request and do stuff, which involves finding the an associated template and then executing whatever's associated with it.
Now, this all works in IIS 5 and 6 and, to an extent, on IIS7 - but for one catch, which happens when you post a form.
See, when you post a form to a non-existent URL, IIS says "ah, but that url doesn't exist" and throws a 405 "method not allowed" error. Since we're telling IIS to redirect those errors to our .aspx page and therefore handling it with our HttpHandler, this normally isn't a problem. But as of IIS7, all POST information has gone missing after being redirected to the 405. And so you can no longer do the most trivial of things involving forms.
To solve this we've tried using a HttpModule, which preserves POST data but appears to not have an initialized Session at the right time (when it's needed). We also tried using a HttpModule for all requests, not just the missing requests that hit 404/403;14/405, but that means stuff like images, css, js etc are being handled by .NET code, which is terribly inefficient.
Which brings me to the actual question: has anyone ever encountered this, and does anyone have any advice or know what to do to get things working again? So far someone has suggested using Microsoft's own URL Rewriting module. Would this help solve our problem?
Thanks.
Microsoft released a hotfix for this :
http://support.microsoft.com/default.aspx/kb/956578
Since IIS7 uses .net from the top down there would not be any performance overhead of using an HttpModule, In fact there are several Managed HttpModules that are always used on every request. When the BeginRequest event is fired, the SessionStateModule may not have been added to the Modules collection, so if you try to handle the request during this event no session state info will be available. Setting the HttpContext.Handler property will initialize the session state if the requested handler needs it, so you can just set the handler to your fancy 404 page that implements IRequiresSessionState. The code below should do the trick, though you may need to write a different implementation for the IsMissing() method:
using System.Web;
using System.Web.UI;
class Smart404Module : IHttpModule
{
public void Dispose() {}
public void Init(HttpApplication context)
{
context.BeginRequest += new System.EventHandler(DoMapping);
}
void DoMapping(object sender, System.EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
if (IsMissing(app.Context))
app.Context.Handler = PageParser.GetCompiledPageInstance(
"~/404.aspx", app.Request.MapPath("~/404.aspx"), app.Context);
}
bool IsMissing(HttpContext context)
{
string path = context.Request.MapPath(context.Request.Url.AbsolutePath);
if (System.IO.File.Exists(path) || (System.IO.Directory.Exists(path)
&& System.IO.File.Exists(System.IO.Path.Combine(path, "default.aspx"))))
return true;
return false;
}
}
Edit: I added an implementation of IsMissing()
Note: On IIS7, The session state module does not run globally by default. There are two options: Enable the session state module for all requests (see my comment above regarding running managed modules for all request types), or you could use reflection to access internal members inside System.Web.dll.
The problem in IIS 7 of post variables not being passed through to custom error handlers is fixed in service pack 2 for Vista. Haven't tried it on Windows Server but I'm sure it will be fixed there too.
Just a guess: the handler specified in IIS7's %windir%\system32\inetsrv\config\applicationhost.config which is handling your request is not allowing the POST verb to get through at all, and it is evaluating that rule before determining whether the URL doesn't exist.
Yes, I would definitely recommend URL rewriting (using Microsoft's IIS7 one or one of the many alternatives). This is specifically designed for providing friendly URLs, whereas error documents are a last-ditch backstop for failures, which tends to munge the incoming data so it may not be what you expect.

Categories

Resources