Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Poul Hansen 5 posts 25 karma points
    Jan 15, 2013 @ 08:54
    Poul Hansen
    0

    404 Response.SetStatus and Blank output

    Hello all,

    I've got something of a weird problem, I've added a custom 404 node, node id number 1193.

    I'm referring to it in umbracoSettings.config

    <error404>1193</error404>

    And i've added the following in the web.config to allow non .aspx pages to also land on it.

    <customErrors mode="On" defaultRedirect="~/404.aspx" />

    And..

     

    <httpErrors errorMode="Custom" existingResponse="Replace" defaultResponseMode="ExecuteURL">
    <remove statusCode="404" />
    <error statusCode="404" prefixLanguageFilePath="" path="/404-that-does-not-exist.aspx" responseMode="ExecuteURL" />
    </httpErrors>

    Now, through debugging and breakpoints i can see that i correctly land on this page, now here comes the weird part (I'm sure there's a logical explaination, so maybe not weird, I'm probably just staring myself blind upon the reason).

     

    If I do not, in the razor code, call the Response.SetStatus to 404, the browser correctly receives the html for the custom 404 page.

    If I do set the status to 404, i correctly get the header that this is a 404, but get absolutely no content (0 bytes of content besides the header)..

    The razor page itself looks like this...

     

    @inherits Umbraco.Web.Mvc.UmbracoTemplatePage
    @{
        Layout = null;
        int statusCode = 404;
        Node currentNode = Node.GetCurrent();
        if (currentNode.HasProperty("errorStatusCode") && !string.IsNullOrWhiteSpace(currentNode.GetProperty("errorStatusCode").Value))
        {
            statusCode = int.Parse(currentNode.GetProperty("errorStatusCode").Value);
        }
        Response.SuppressFormsAuthenticationRedirect = true;
        Response.ContentType = "text/html";
        Response.TrySkipIisCustomErrors = true;
        Response.SetStatus(HttpStatusCode.NotFound);
    }
    <html>
    <head>
        <title>@Umbraco.Field("errorTitle")</title>
    </head>
    <body>
        <h1>@Umbraco.Field("errorTitle")</h1>
        <p>@Umbraco.Field("errorText")</p>
    </body>
    </html>

     

    I've tried Googling for a problem like this but haven't really found any problems quite like this one...

     

  • Mike Chambers 636 posts 1253 karma points c-trib
    Jan 15, 2013 @ 10:45
    Mike Chambers
    0

    yep I had this same issue but in a webforms u 4.11 site.

    I've stumbled on a different workaround, a little strange but seems to work

    I have the 404 page set in the umbracosettings and that serves fine for aspx pages (status code is 404)

    however, I could only get a status code of 200 setting the httperrors...

    So what I did was web.config, 

    I didn't add the <customErrorsmode="On"defaultRedirect="~/404.aspx"/>

    but in the httperrors

    <httpErrors errorMode="Custom"> <remove statusCode="404" subStatusCode="-1" /> <error statusCode="404" prefixLanguageFilePath="" path="/5820.aspx" responseMode="ExecuteURL"/> </httpErrors>

    and here's the rub... the path value is an id that doesn't exist, so at that point umbraco handle404 should intercept and give the 404 page with a status of 200, but for some reason it still doesn't.

    So I just recreated my own 404 handler and added to the 404handlers.config and that seems then to pick up and redirect to the 404 page with a 200 status code.

    public class FidusCMS404Redirect : INotFoundHandler
        {
            private int _redirectID = -1;
    
            #region INotFoundHandler Members
    
            public bool CacheUrl
            {
                get
                {
                    return false;
                }
            }
    
            public bool Execute(string url)
            {
    
                if (umbraco.UmbracoSettings.UseDomainPrefixes)
                {
                    // we have multiple domains, try and map 404's
                    XmlNode error404Node = UmbracoSettings.GetKeyAsNode("/settings/content/errors/error404");
    
    
                    if (error404Node.ChildNodes.Count > 0 && error404Node.ChildNodes[0].HasChildNodes)
                    {
                        // try to get the 404 based on current domain
                        XmlNode domainErrorNode;
                        string CurrentDomain = System.Web.HttpContext.Current.Request.Url.Host.ToLower();
    
                        // try match to domain
                        domainErrorNode = error404Node.SelectSingleNode(String.Format("errorPage [@domain = '{0}']", CurrentDomain));
    
                        try
                        {
                            _redirectID = int.Parse(domainErrorNode.FirstChild.Value);
                        }
                        catch
                        {
                            domainErrorNode = error404Node.SelectSingleNode(String.Format("errorPage [@domain = '{0}']", "default"));
    
                            try
                            {
                                _redirectID = int.Parse(domainErrorNode.FirstChild.Value);
                            }
                            catch
                            {
                                _redirectID = Convert.ToInt32(UmbracoSettings.GetKey("/settings/content/errors/error404"));
                            }
                        }
    
                    }
                    else
                    {
                        _redirectID = Convert.ToInt32(UmbracoSettings.GetKey("/settings/content/errors/error404"));
                    }
    
                }else{
                    _redirectID = Convert.ToInt32(umbraco.UmbracoSettings.GetKey("/settings/content/errors/error404"));
                }            
    
                umbraco.BusinessLogic.Log.Add(umbraco.BusinessLogic.LogTypes.NotFound, _redirectID, "404 Redirect - " + HttpContext.Current.Request.Url);
                //301 rather than just 404
                //HttpContext.Current.Response.Status = "301 Moved Permanently";
                //HttpContext.Current.Response.AddHeader("Location", umbraco.library.NiceUrl(_redirectID));
    
                return true;
            }
    
            public int redirectID
            {
                get
                {
                    //return 1983;
                    return _redirectID;
                }
            }
    
            #endregion
        }


    Sort of a double take.. but seems to work.

     

    Not sure if this approach is posible in MVC... ???  

  • Poul Hansen 5 posts 25 karma points
    Jan 16, 2013 @ 06:25
    Poul Hansen
    0

    I ended up hijacking the route with a custom controller, when i set the 404 status in the custom controller and then outputting the view, i both get content and the correct status code.

  • Poul Hansen 5 posts 25 karma points
    Jan 16, 2013 @ 06:34
    Poul Hansen
    0

    I ended up hijacking the route with a custom controller, when i set the 404 status in the custom controller and then outputting the view, i both get content and the correct status code.

    I did this due to testing the whole setting the statuscode on the razor page for another page, and i got exactly the same issue..

    So what i did was a Custom controller for the error page..

     

        publicclassCustomErrorController : RenderMvcController

     

        {

     

            public ActionResult Index(RenderModel model)

     

            {

     

                Response.TrySkipIisCustomErrors = true;

     

     

     

                int statusCode = 404; // Default

     

     

     

                if (model.Content.GetProperty("errorStatusCode") != null && !string.IsNullOrWhiteSpace(model.Content.GetProperty("errorStatusCode").Value.ToString()))

     

                {

     

                    statusCode = int.Parse(model.Content.GetProperty("errorStatusCode").Value.ToString());

     

                }

                

                Response.StatusCode = statusCode;

     

     

     

                return base.Index(model);

     

            }

     

        }

    (Why can't i mark the above as code??)

    This allows me to set it pretty easily, i can also easily make a corresponding error 500 page, but with a different template for another text, but using the same document type to route it through the controller..

    Thanks anyway for your extensive response Mike :)

     

Please Sign in or register to post replies

Write your reply to:

Draft