2

I've got the following IHttpModule and I'm trying to figure out how to execute an action from a controller for a given absolute or relative URL.

public class CustomErrorHandlingModule : IHttpModule
{
    #region Implementation of IHttpModule

    public void Init(HttpApplication context)
    {
        context.Error += (sender, e) => 
            OnError(new HttpContextWrapper(((HttpApplication)sender).Context));
    }

    public void Dispose()
    {}

    public void OnError(HttpContextBase context)
    {
        // Determine error resource to display, based on HttpStatus code, etc.
        // For brevity, i'll hardcode it for this SO question.
        const string errorPage = @"/Error/NotFound";

        // Now somehow execute the correct controller for that route.
        // Return the html response.
    }
}

How can this be done?

George Stocker
  • 57,289
  • 29
  • 176
  • 237
Pure.Krome
  • 84,693
  • 113
  • 396
  • 647

4 Answers4

8

Something along the lines should do the job:

public void OnError(HttpContextBase context)
{
    context.ClearError();
    context.Response.StatusCode = 404;

    var rd = new RouteData();
    rd.Values["controller"] = "error";
    rd.Values["action"] = "notfound";
    IController controller = new ErrorController();
    var rc = new RequestContext(context, rd);
    controller.Execute(rc);
}

You might also find the following related answer useful.

Community
  • 1
  • 1
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Surely you'd want to set the error code inside the error controller, rather than before? Maybe I'm missing something. – Simon Halsey Aug 07 '11 at 21:46
  • @Darin Dimitrov - awesome dude :) But, notice how u have hardcoded your controller and action? Is it possible to do this with a uri already determined? eg. url = ;foo/bah/pewpew/notfound` ? – Pure.Krome Aug 08 '11 at 01:38
  • @Pure.Krome, IMHO `foo/bah/pewpew/notfound` is far more hardcoded than my solution as it would be more fragile to route changes. – Darin Dimitrov Aug 08 '11 at 13:09
  • @Darin Dimitrov - in my example that was hardcoded. in reality, i would read the url from the customErrors section of the we.config, erros subsection for the http status code OR default error page if no specific route was provided for the error code. – Pure.Krome Aug 09 '11 at 04:36
  • @Pure.Krome, in this case instead of putting an entire url in your web.config put the controller and action that should be rendered. – Darin Dimitrov Aug 09 '11 at 14:35
1

I think you need to use HttpContext.Current.RewritePath

This lets you change the path for the file you want to use. It's what the default.aspx created in MVC 2 projects does.

I've used it in much the same way you are, to do error handling without a 302 but can't get to my code right now. I'll post some code on Monday.

George Stocker
  • 57,289
  • 29
  • 176
  • 237
Simon Halsey
  • 5,459
  • 1
  • 21
  • 32
0

You can using HttpContext:

System.Web.HttpContext.Current.Response.Redirect("/Error/NotFound");
Brian Mains
  • 50,520
  • 35
  • 148
  • 257
  • Nope -> please re-read the question. This will do a 302 temp redirect AND set the url to be `/Error/NotFound` .. which is not what I'm after. This is the default scenario when you use `CustomErrors`. – Pure.Krome Aug 07 '11 at 12:35
  • Oh - one more thing. The error page will then respond with a 200 STATUS OK, which is wrong (unless u do some special code to force the page's `HttpStatus`). – Pure.Krome Aug 07 '11 at 12:42
0

Hi use this to let the framework execute the code for that path using the routing and all the components :

    // MVC 3 running on IIS 7+
    if (HttpRuntime.UsingIntegratedPipeline)
    {
        context.Server.TransferRequest(url, true);
    }
    else
    {
        // Pre MVC 3
        context.RewritePath(url, false);

        IHttpHandler httpHandler = new MvcHttpHandler();
        httpHandler.ProcessRequest(httpContext);
    }

And ideally the request processing is completer at this point. If this is not the case and if the request is further processed along the asp.net http pipeline, then use this to stop the request at this point, and tell asp.net that we're done with this request :

HttpApplication app = (HttpApplication) context.Application;
app.CompleteRequest();;

Im not sure if the context has the Application (im not near VS now) but use it to stop the request in this module if needed.

Zasz
  • 12,330
  • 9
  • 43
  • 63
  • Also go to this link : http://stackoverflow.com/questions/799511/how-to-simulate-server-transfer-in-asp-net-mvc – Zasz Aug 07 '11 at 18:41