views:

94

answers:

5

Hi,

i was wondering about the following:

i can define in IIS what to do with page not founds / 404, and also in my app i can put it in my CustomErrors section or just handle it in code.

Now as i assume IIS always gets the request first, when does it handle the 404 for itself, and when does it let it pass through to my app?

And a side-question: can IIS actually know if a request in asp.net MVC is a 404 because it might or it might not me mapped via any route?

+1  A: 

IIS looks at the request extension. If there is a module registered to handle the type of request that came in, then it will forward the request to that module.

For example, if you request foo.jpg from your server, then IIS has a module built in to handle image/jpg content. If that module can't find the file then it returns a 404.

Same thing here. Whatever your MVC handlers don't look for (ie: images), then IIS will take care of in another manner.

Chris Lively
+1  A: 

can IIS actually know if a request in asp.net MVC is a 404 because it might or it might not me mapped via any route?

I think it all depends on how your controller factory handles the unmapped request. The DefaultController factory seems to throw an HttpException with code 404 when it cannot find a route and let IIS handle the error display. You can play with this and see it in action by creating your own controller factory.

For example, add the following line to your Application_Start

ControllerBuilder.Current.SetControllerFactory(new TestControllerFactory());

and add this class to a brand new MVC project:

public class TestControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            //throw new Exception("Oops!");                               // yellow screen of death
            throw new System.Web.HttpException(404, "Oops not found!"); // bubbles up to IIS
        }
        return base.GetControllerInstance(requestContext, controllerType);
    }
}

Navigate to your project to http://localhost/MvcApplication1/unmapped and see what happens when you throw an HttpException with code 404 versus when you throw a regular Exception (or even an HttpException with a code other than 404)

Make sure you are running your project under IIS (rather than the VS Dev Server) as the they handle these things different.

Hector
+1  A: 

Now as i assume IIS always gets the request first, when does it handle the 404 for itself, and when does it let it pass through to my app?

Although the request is initially handled by ISS, it passed through to the MVC application. If a file is not found, an HttpException is thrown which bubbles back to IIS. If a file is found, it is served directly bypassing routing.

However, you can modify the behaviour by adjusting the the RouteExistingFiles property. If I'm not mistaken though you will need to create a route to handle all static content when the property is set to true (default is false). However, as a post here suggests, as per Steve Sanderson, that the routing system will first check if the file exists on disk. (See this related SO question which provides better clarification, especially the comments).

Try it yourself. Use the Application_Error() and Application_EndRequest() events in the Global.asax file and inspect the HttpContext.Current.Response object to to see what the final responses are when content is being served.

And a side-question: can IIS actually know if a request in asp.net MVC is a 404 because it might or it might not me mapped via any route?

This is where route configuration comes into play. Since MVC will check to see if the file exists first, if it does, it gets served directly and routing is bypassed. With regards to Controllers and actions, the same will apply. Eg. /SomeController/ActionThatDoesExist is first checked to verify if it is a physical file. Clearly this is not a file and a 404 exception will be returned from the application.

The third aspect I think that may be related to this question is how MVC and IIS work together. By this I am referring to Integrated Mode and Classic Mode. An awesome explanation can be found here.

Ahmad
A: 

You will want to keep the execution within your MVC app and like others have said, usually IIS will pass the request into MVC first and only then if MVC passes a 404 exception up high enough will IIS get it back and apply it's decision making process.

The key is: handle 404's in MVC properly!

cottsak
+1  A: 

IIS always handles the request and then forwards it to the MVC application. This is where it is basically decided how to handle it.

If their is already a physical file on the disk, then the whole Routing is bypassed and the file is served. If it can't find the file then it tries matching the Routing. If nothing works then the MVC application may handle the 404 otherwise it throws the HTTPException and IIS handles the 404.

I believe even in Webforms, the 404 scenario is pretty much the same internally. Only difference being the target is always a physical disk but the request still goes to ASP.NET Webforms, incase you want to handle the 404 yourself.

nEEbz