0

I have an ASP.NET MVC application, that is deployed in the Default web site in IIS and it runs inside an application folder, e.g. http://localhost/appfolder.

I have two error pages and I tried to set them using the <httpErrors> section in web.config.

<httpErrors errorMode="Custom" existingResponse="Replace">
    <remove statusCode="401" />
    <remove statusCode="500" />
    <error statusCode="401" responseMode="ExecuteURL" path="/appfolder/Home/NoAccess" />
    <error statusCode="500" responseMode="ExecuteURL" path="/appfolder/Home/Error" />
</httpErrors>

The above setup works, but I could not make it work without using the folder name inside the paths. Based on the documentation the path attribute is relative to the site root.

If you choose the ExecuteURL response mode, the path has to be a server relative URL (for example, /404.htm).

So, with the above in mind, the following should work, but it doesn't.

<httpErrors errorMode="Custom" existingResponse="Replace">
    <remove statusCode="401" />
    <remove statusCode="500" />
    <error statusCode="401" responseMode="ExecuteURL" path="/Home/NoAccess" />
    <error statusCode="500" responseMode="ExecuteURL" path="/Home/Error" />
</httpErrors>

Also, using ~/Home/NoAccess does not work at all, it seems that IIS simply puts ~ in the URL.

My question: Is it possible to have the above setup without having to use application folder name?

Edit: See in this snippet how my application is authorizing each request.

public class AppAutorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        bool authorized = false;
        // Business logic to decide if authorized
        return authorized;
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        base.HandleUnauthorizedRequest(filterContext);
    }
}

And its use in a controller is:

[HttpGet]
[AppAutorize]
public ActionResult Item(int id)
{
    Models.Home.Item model = new Models.Home.Item(id);

    return View("Item", model);
}

1 Answer 1

1

Because your web application is hosted under another website the correct site relative path for the error pages would be the one you said works. I know this isn't what you was hoping to see but the best way of handling this is to replace that httpErrors element in the Web.Release.config file like the following:

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document Transform">
    <system.webServer>
        <httpErrors xdt:Transform="Replace">
            <remove statusCode="401" />
            <remove statusCode="500" />
            <error statusCode="401" responseMode="ExecuteURL" path="/appfolder/Home/NoAccess" />
            <error statusCode="500" responseMode="ExecuteURL" path="/appfolder/Home/Error" />
        </httpErrors>
    </system.webServer>
</configuration>

And keep the standard Web.config with the path excluding the appfolder path.

How I tend to do it

I tend to shy away from using the web config and instead set the HTTP errors to the following:

<httpErrors errorMode="DetailedLocalOnly" existingResponse="PassThrough" />

I then have a base controller which all my controllers inherit from with methods for each error code which I want a custom page for. So in your case:

public ViewResult NoAccess()
{
    Response.StatusCode = (int) HttpStatusCode.Unauthorized;

    return View("NoAccess");
}

Then the usage in any of your controllers is very simple:

public ActionResult Test()
{
    return NoAccess();
}

This will then render your custom view. This method of doing error pages depends on your use case but that's how I've managed to get custom error pages to work.

Sign up to request clarification or add additional context in comments.

4 Comments

Hey David, thanks for the answer. From what I have searched so far, I also feel it would be better to move my approach from the web.config file. In my project though, the decision whether a request is authorized or not, is made in a System.Web.Mvc.AuthorizeAttribute, and there I am not sure if I can redirect each request to my NoAccess controller.
@TasosK. That's very simple, the way I got around that was simply creating a new AuthorizeAttribute and inherit from the old one. Then override the method HandleUnauthorizedRequest and add a simple redirect to the error page
I have tried your approach but I didn't like the fact that upon redirection, the URL in the browser changes, something that is not what I want. But I guess this is outside from the strict context of my question.
@TasosK. Instead of sending out a redirect you are able to modify the Response directly and return a specific view if that's what you wish to do. I redirect users because if I want to change the view at a later date I don't have to modify it in multiple locations.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.