MVC Redirect

Topics: MVC
Jan 13, 2011 at 8:14 AM

Hi,

When trying to return a RedirectResult instead of an ActionResult the application crashes with following error:

Server Error in '/' Application.
Thread was being aborted.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Threading.ThreadAbortException: Thread was being aborted.

Source Error:

Line 89: 
Line 90:         IEnumerable contents = PageManager.GetPlaceholderContent(page.Id);
Line 91:         Control renderedPage = PageRenderer.Render(page, contents);
Line 92:         this.Controls.Add(renderedPage);
Line 93:         if (this.Form != null) this.Form.Action = Request.RawUrl;


Source File: c:\...\Website\Renderers\Page.aspx.cs    Line: 91 

Any idea how to safely redirect to a URL when using MVCPlayer function?

Jan 13, 2011 at 8:30 AM

I modified \Renderers\Page.aspx.cs Line : 91,92 from :

        Control renderedPage = PageRenderer.Render(page, contents);
        this.Controls.Add(renderedPage);

to :

        try
        {
            Control renderedPage = PageRenderer.Render(page, contents);
            this.Controls.Add(renderedPage);
        }
        catch (System.AggregateException ex)
        {
            if (ex.InnerException.GetType() == typeof(System.Threading.ThreadAbortException))
            {
                //The Page renderer was aborted. Possibility of an internal redirect.
            }
            else
                throw ex;
        }

I simply put it in a try catch clause and now it's working.

Any suggestion?

Jan 13, 2011 at 8:37 AM

Seems like a combination of things... im not a MVC expert, but in plain asp.net you have the possibility to pass a false when calling Response.Redirect. The false will tell the runtime NOT to about the thread but just silently set the StatusCode and RedirectLocation and let the rest of the Request execute normally.

Are you able to tell in the RedirectResult that the thread should NOT be aborted?

Other than that, it clearly smells of a bug in the Rendering mechanism of C1, maybe in some parallelism code not handling a ThreadAbortException.

 

 

Jan 13, 2011 at 8:45 AM

I don't think there is such option in MVC Redirect or at least I'm not aware of.

I agree with you that this looks like a bug.

Jan 13, 2011 at 8:52 AM
Edited Jan 13, 2011 at 9:25 AM

I have filed a bug here http://compositec1.codeplex.com/workitem/512

In the meantime it seems like people are subclassing the RedirectResult-class and overriding the ExecuteResult method so it DOESN'T aborts the thread after setting RedirectLocation. Only reason you should bother doing this, instead of just sticking with the fix you made to page.aspx is if you don't want to make changes to the C1 source in case of updates that will overwrite your changes.

Such a class could look like this

 

public class MyRedirectResult : RedirectResult
{
    private bool _endRequest;

    public MyRedirectResult(string url)
        : this(url, true)
    {
    }

    public MyRedirectResult(string url, bool endRequest)
        : base(url)
    {
        _endRequest = endRequest;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        var ctx = HttpContext.Current;

        ctx.Response.Redirect(Url, _endRequest);
    }
}

 

Jan 13, 2011 at 9:15 AM

This sounds like a better solution and since I am developing a package it's better to not touch the source.

Anyway, here is the code I put in Company.dll with a bit modification:

using System.Web;

namespace Company
{
    public class RedirectResult : System.Web.Mvc.RedirectResult
    {
        private bool _endRequest;

        public RedirectResult(string url)
            : this(url, true)
        {
        }

        public RedirectResult(string url, bool endRequest)
            : base(url)
        {
            _endRequest = endRequest;
        }

        public override void ExecuteResult(System.Web.Mvc.ControllerContext context)
        {
            HttpContext.Current.Response.Redirect(Url, _endRequest);
        }
    }
}

Here is how I used it in MVC :
return new Company.RedirectResult(url, false);

Jan 13, 2011 at 9:23 AM

Beautiful, just as it should be... and now i'm off to bed! (its 6:22 am here in Greenland :P)

Jan 13, 2011 at 9:24 AM

Sweet dreams. :)

Feb 18, 2011 at 9:16 AM

Do you still have this problem with never builds and when using the System.Web.Mvc.RedirectResult class directly?

Feb 18, 2011 at 10:16 AM

Haven't tried it with newer release yet. Is there any beta version released or should I build one from source code?