(I'm about to answer this question as well, because I've found the solution, but Google didn't really help, so hopefully this will gain some PageRank for the search terms I was using.)
We have a big Umbraco site with several sections, but most locales don't have section homepages. So if the structure looks like:
- Homepage
- Section1
- Page1-1
- Page1-2
- Section2
- Page2-1
- Page2-2
and so on, then going to ~/section1/
would redirect you to ~/section1/page1-1/
(and, likewise ~/section2/
redirects you to ~/section2/page2-1/
).
At the moment, we use a macro that checks a property in the locale homepage and then redirects:
var node = Model.AncestorOrSelf("SiteHome");
var useCSSV2 = node.GetProperty("useCSSV2").Value;
if (useCSSV2 == "1")
{
Response.Redirect(Model.Children.First().Url);
}
We're seeing a bunch of occasions where macros don't load properly, with errors like
Error loading MacroEngine script (file: PrimaryNavigationSwitcher.cshtml)
displaying instead. Looking at the UmbracoTraceLog, I can see things like:
2014-11-25 00:11:28,226 [5] WARN umbraco.macro - [Thread 39] Error loading MacroEngine script (file: PrimaryNavigationSwitcher.cshtml, Type: ''. Exception: System.Threading.ThreadAbortException: Thread was being aborted.
at System.Threading.Thread.AbortInternal()
at System.Threading.Thread.Abort(Object stateInfo)
at System.Web.HttpResponse.AbortCurrentThread()
at System.Web.HttpResponseWrapper.Redirect(String url)
at ASP._Page_macroScripts_SecondLevelPageRedirection_cshtml.Execute() in d:\webroot\www.mysite.com\macroScripts\SecondLevelPageRedirection.cshtml:line 8
at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
at System.Web.WebPages.WebPage.ExecutePageHierarchy()
at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
at umbraco.MacroEngines.RazorMacroEngine.ExecuteRazor(MacroModel macro, INode currentPage)
at umbraco.MacroEngines.RazorMacroEngine.Execute(MacroModel macro, INode currentPage)
at umbraco.macro.loadMacroScript(MacroModel macro)
at umbraco.macro.renderMacro(Hashtable pageElements, Int32 pageId)
(where line 8 of SecondLevelPageRedirection.cshtml is the Response.Redirect).
That problem and the ThreadAbortException itself are strongly suggesting to me that Response.Redirect is the problem here and I should be using some other means of performing this redirect. (And even if this weren't a problem I'd prefer to avoid the performance impact of a bunch of exceptions being thrown.)
How should we be performing this redirect to have the same effect (so anyone going to ~/section1
/ will be redirected to ~/section1/page1-1/
and so on), without having to add an umbracoRedirect
or umbracoInternalRedirectId
to each node and without having these damn ThreadAbortExceptions thrown all the time?
As detailed in a handful of places (notably Why Response.Redirect causes System.Threading.ThreadAbortException? here on Stack Overflow and PRB: ThreadAbortException Occurs If You Use Response.End, Response.Redirect, or Server.Transfer on the MSKB),
Response.Redirect(string)
is only present in ASP.Net for backwards compatibility.To quote from Joel Fillmore in his answer to the Stack Overflow question linked above:
Note that code after the
Context.ApplicationInstance.CompleteRequest
call will execute, so may need handling separately.Incidentally, as the problem stems from
Response.End
, which includes the codethen
Server.Transfer
will have precisely the same problem. There is more information at IsResponse.End()
considered harmful?