3
votes

I need to redirect from non-existent document in CMS to existing ones

I have an Umbraco instalation and old links in old CMS. I need these old links to be redirected to the new structure in umbraco, but as structure of each of the CMSs is different, I need to setup some kind of rules.

My first idea was setup IIS that when it (Umbraco) returns 404 there will be another internal redirect (if original request mathced some rule). I presume the way will eventually go through URL rewrite but I wasn't able to set it up correctly.

There are possibly hundreads of pages for redirection so i would like this to be handled by server and not by the aplcication itself for performance issues.

3

3 Answers

0
votes

In /Config/umbracoSettings.config you can configure node that will handle all of your not found pages

<errors>
<!--
    <error404>
        <errorPage culture="default">nodeId</errorPage>
    </error404>
-->

nodeId is just a regular node with the template so you can put your logic in there.

0
votes

You can set up a document type for your Error page and then handle the processing in the template or a Controller, redirecting to another page depending on the request URL etc. I frequently use this to suggest related or similar pages based on the request URL.

0
votes

OK, at the end the sollution was creation of custom HTTP module

public class Redirector : IHttpModule
    {
        #region --- Private Properties ---
        private static Logger logger = LogManager.GetCurrentClassLogger();
        private static ConcurrentDictionary<string, string> Dictionary = new ConcurrentDictionary<string, string>();
        #endregion


        #region --- LifeCycle ---
        public void Dispose()
        {

        }

        public void Init(HttpApplication context)
        {
            logger.Error("RedirectModule: I have been initialized");
            FillDictionary();

            context.EndRequest += EndHandler;

        }

        public bool IsReusable
        {
            get { return true; }
        }

        private void FillDictionary()
        {
            logger.Error("Filling dictionary");
            try
            {
                var currentDir = Directory.GetCurrentDirectory();

                ResourceManager rm = new ResourceManager("Resources.resx",
                Assembly.GetExecutingAssembly());

                var text = Resources.DICTIONARY_FILE;
                var parsedText = text.Split('\n');
                foreach (var row in parsedText)
                {
                    var split = row.Split(';');
                    if (split == null || split.Length != 2)
                    {
                        continue;
                    }

                    if(!Dictionary.ContainsKey(split[0]))
                    {
                        logger.Trace($"Adding key {split[0]}");
                        Dictionary.TryAdd(split[0], split[1]);
                    }                    
                }

            }
            catch(Exception exception)
            {
                logger.Error(exception, "Unable to fill dictinary");
            }
        }

        #endregion

        #region --- Handlers ---

        private void EndHandler(object sender, EventArgs e)
        {
            logger.Trace("RedirectModule: End of reqest catched");
            try
            {

                HttpApplication application = (HttpApplication)sender;
                var code = application.Response.StatusCode;
                Exception currentException = application.Server.GetLastError();
                HttpException httpException = currentException != null ? (currentException as HttpException) : null;
                HttpContext context = application.Context;

                if (httpException != null)
                {
                    if (httpException.GetHttpCode() == 404)
                    {
                        logger.Trace($"RedirectModule: 404 catched in ending as exception, original path: {context.Request.Url}");
                        if (Dictionary.ContainsKey(context.Request.Url.ToString()))
                        {
                            context.Response.Redirect(Dictionary[context.Request.Url.ToString()]);
                            logger.Trace($"redirecting to {Dictionary[context.Request.Url.ToString()]}");
                        }
                        else
                        {
                            logger.Trace($"Dictionary contains no record for  {Dictionary[context.Request.Url.ToString()]}");
                            logger.Trace($"Current amount of keys in dictionary is: {Dictionary.Count}");
                        }
                    }
                    else
                    {
                        logger.Error("RedirectModule: Unknown catched as ending");
                    }
                }
                else if (code == 404)
                {
                    logger.Trace($"RedirectModule: 404 catched in ending with no exception, original Url: {context.Request.Url}");
                    if (Dictionary.ContainsKey(context.Request.Url.ToString()))
                    {
                        context.Response.Redirect(Dictionary[context.Request.Url.ToString()]);
                        logger.Trace($"redirecting to {Dictionary[context.Request.Url.ToString()]}");
                    }
                    else
                    {
                        logger.Trace($"Dictionary contains no record for  {Dictionary[context.Request.Url.ToString()]}");
                        logger.Trace($"Current amount of keys in dictionary is: {Dictionary.Count}");
                    }
                }
                else if(code != 200)
                {
                    logger.Trace("Some other error code catched");
                }
            }
            catch (Exception exception)
            {
                logger.Error(exception, "RedirectModule: Encountered and exception");
            }
        }

        #endregion


    }
}

It takes its settings from resourcefile and redirects to the requested pages. The only setback is that I didn't manage to create custom settings xml for redrection settings so it needs to be recompiled every time the setting changes (does enyone know how to do it? Starting location of httpmodule makes it difficult to load anything form file).

My thanks to Robert Foster who pointed me in this direction.