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 621 posts 1203 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 :)

     

  • This forum is in read-only mode while we transition to the new forum.

    You can continue this topic on the new forum by tapping the "Continue discussion" link below.

Please Sign in or register to post replies