Sitecore ‘Redirect Manager’ module available on shared source.

A quick post to say that I’ve finally uploaded my shared source ‘Redirect Manager’ module to http://trac.sitecore.net/RedirectManager/

A picture speaks a thousand words, so you should get the idea from this :

Sitecore redirect manager shell screenshot

Key features

  • Shell – displays links for current item, redirects, and aliases.
  • Automatic 301 record generation of historic links (renamed, moved, or even structural changes)
  • Manual 301 record generation via right-click or ribbon.

Publishing any item clears the redirect cache. (required after manual redirect creation).

Performance

Rough tests with 100,000 redirect records :

Preload delay: 150-250ms (loads into lookup cache, on startup or after publish)
Http processor delay: roughly 0.15ms (~373 ticks)

See the main trac page for download and install instructions.

Enjoy!

31 thoughts on “Sitecore ‘Redirect Manager’ module available on shared source.

  1. Rickard Andersson

    Hi Paul,

    First off, thanks for what looks like an excellent module. It’s exactly what I want for a client I’m working with. However, I’m having a few issue that maybe you can clear up for me.

    There appears to be a bug in the module when it comes to query strings. I can add a redirect URL that contains a query string, but it appears as if the query string is ignored in the lookup. Also, once you’ve added a redirect with a query string, you can’t delete it. It throws an exception.

    The reason I’m asking is because the client I’m working with is migrating from an old in-house developed CMS that uses query strings extensively. I am required to redirect from e.g. “/foo/bar.asp?id=some page name”.

    I haven’t had a close look, but how’s the support for CM/CD environments? Since the module uses its own database, I’m guessing that’s a no-go unless all CD servers also have access to the database?

    Cheers,
    Rickard

    Reply
    1. Paul George

      Hi,

      Thanks for your comment. The module currently works by looking at the request path only, everything else (i.e. protocol, host or domain, querystring, fragment) is ignored. This is compared in a case-insensitive manner to the stored redirects, which themselves are expected to be just url paths. There’s obviously some validation (or rather my hidden assumptions) missing there.

      While I understand your requirement to redirect different querystring urls to different targets, it is also a feasible requirement to want to ignore different querystring parameters and redirect any request to a url path to a nominated target (this should be the current behaviour).

      CM/CD environs – I guess its the same for the other shared databases, like core or security. The module is not database aware. Early versions were, and also stored redirects as sitecore items, but that was dropped due to the performance benefits of using a real SQL db, which in turn made automatic 301 handling possible (to be explained in another post). Entirely untested, but you could host the redirect DB in the live environment, and connect to it from the CM environment (same as some scaling configs). You would need to be aware that the data is shared, so redirects created are immediately live as far as SQL goes (still requires cache to be cleared).

      Reply
      1. Rickard Andersson

        Thank you for your answer.

        While I agree that being able to ignore query strings is a feasible requirement, in my case, I need them. Based on your comment though, I’m guessing I shouldn’t wait up for a new version of the module that supports query strings? 🙂

        I understand regarding the CM/CD situation. The issue in my case is that we have multiple CD servers that are geographically separated so that latency becomes an issue. A CD server in Japan can’t rely on a SQL server in the UK. In order to use this module, we would have to setup SQL replication.

        Cheers,
        Rickard

        Reply
        1. paul Post author

          Regarding CM/CD locations, it’s a tricky problem. Originally I went down the route of storing redirects as sitecore items, settings their display name as the url path and so on. This was so that the module would just run ‘out-of-the-box’ It worked fine, but 2000 sitecore redirect items took something like 4000ms to load into the dictionary cache. This would mean that geographic publishing would work as ‘normal’ in Sitecore terms, but the speed would rule out automatic redirect feature, which relies on creating a ‘redirect’ record of item as they are published, or in other words, you store (numberOfContentItems + subsequent item name changes), not just records when something changes. Using SQL instead of Sitecore items I could load 100,000 records in around 200ms (and on just a laptop), which makes this approach very viable.

          I felt that automatic 301 redirects was such a useful feature that I ditched all the original work and just used a simple SQL provider instead. I detailed some of this at the Sitecore London user group a few weeks ago in early Feb. I may have an idea for how to mix these two approaches, but I need to check a few things out first.

          Reply
  2. Madhumidha Anbalagan

    Hi Paul,
    I am running into a publishing error. Below is the error, I got while publishing.

    Am I missing something ? Any suggestions ? Also I found a forum post on this topic – http://sdn.sitecore.net/SDN5/Forum/ShowPost.aspx?PostID=44085#44085

    Job started: Publish to ‘web’|#Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. —> System.UriFormatException: Invalid URI: The format of the URI could not be determined.
    at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
    at RedirectManager.Pipelines.PublishItem.Processor.Process(PublishItemContext context)
    at (Object , Object[] )
    at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
    at Sitecore.Publishing.Pipelines.PublishItem.PublishItemPipeline.Run(PublishItemContext context)
    at Sitecore.Publishing.Pipelines.Publish.ProcessQueue.ProcessEntries(IEnumerable`1 entries, PublishContext context)
    at Sitecore.Publishing.Pipelines.Publish.ProcessQueue.Process(PublishContext context)
    at (Object , Object[] )
    at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
    at Sitecore.Publishing.Pipelines.Publish.PublishPipeline.Run(PublishContext context)
    at Sitecore.Publishing.Publisher.Publish()
    — End of inner exception stack trace —
    at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
    at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
    at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
    at (Object , Object[] )
    at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
    at Sitecore.Jobs.Job.ThreadEntry(Object state)

    Reply
      1. Jørn

        Hi,
        I am experiencing the same problem. The error message appears only when the attribute “hostName” is defined in the “” section in web.config.

        Reply
        1. paul Post author

          Hi,

          I can’t currently reproduce this, with or without a hostname attribute defined. Can you describe your config again or send me an email to paul {at} (this domain)?

          Reply
          1. paul Post author

            Thank you Jørn – I finally managed to spend some time on this. This issue is caused by the linkmanager generating links without a scheme, i.e. starting with :// instead of http:// . This happens only when a single host name is specified in the site definition.

            This is turn throws a url parsing error which is now caught and logged but the redirect is not generated.

            This can be addressed by adding scheme=”http” to the site definition when the host attribute is used. Additionally, a fix has been added to the module source to add ‘http’ as a default scheme if LinkManager generates a link without one.

            An updated module should should be released shortly via Codeplex.

  3. Fruber Malcome

    Trying to understand how this hooks into sitecore; I don’t see the class library referenced in any of the config files; so how does sitecore know to load the RedirectManager library. Have a setup where there is a staging server – which has a core/master/web and then a production server that shares the core and has it’s own web (databases). So installing on staging server is easy (typicall package install) – but can’t seem to get the library to load on the production server.

    What settings are necessary to make it work in this scenario?
    Any help would be appreciated.
    thanks.

    Reply
    1. Fruber Malcome

      Figured it out; it was through the additional include which inserted a pipeline for it.

      I’ve modified my current version to support regex if anyone is interested.

      Reply
        1. Fruber Malcome

          I store them as a regular string (formatted as regex). I modified the collection/dictionary that is being used to locate the url to first generate a regex object based on the string/url being passed and then tries to match each.

          Reply
  4. David Stöger

    Hi Paul,

    Is there a dialog which shows up all url redirects that are entered? Is there a way to define redirects like
    I want every request likt /company/(.*) redirected to /company/new-structure/$1?

    Thanks,
    David

    Reply
    1. paul Post author

      Hi,

      Wildcards are not currently supported, although I believe that a different module, the “301 redirect module” supports regex, which sounds like it will do what you want.

      Reply
      1. David Stöger

        Hi Paul,

        Thank you for your reply. Yes, the 301 redirect module does support regex. I like the approach of using a database. But what am I missing is a list of all redirects applied. Furthermore, not all redirects are always bound to an item (e.g. when you use regex, but as it is currently not supported this is not the problem). but anyway, a list of all redirects would be cool to fast add, remove, delete, delete all..

        Best Regards,
        David

        Reply
  5. Sumith

    Hi,
    With MaxItemNameLength set to 100, When we create a redirect it fails. how can we add long item urls. also the RequestPath column length in the database is set to 255. that means its not going to work for url longer than that. Is anyone facing the same problem. Should we not change to the max to supported browser length ‘ 2,000’ or more.
    Cheers
    S

    Reply
  6. paul Post author

    This project is now hosted on Codeplex. An updated version of this module has been packaged as v0.5.

    As well as many minor changes, this fixes a critical issue with url language prefixes and also changes the DB storage of urls to NVarChar 400 to cater for longer urls.

    Reply
  7. Anthony

    I have been looking for a redirect solution and was originally using the sitecore item version which never seemed to work and does not seem to be supported any longer. I installed this package. Created the database. Added the connection string. I can now create the redirect link in Sitecore, but when I test it out, I just get the usual 404 page. Am I missing something?

    Reply
  8. paul Post author

    Anthony – The module is added to the request pipeline by dropping RedirectManager.config into the the \App_Config\Include folder. Check the logs, there should be something there.

    Reply
    1. Anthony

      I was able to get the redirects to work. It was actually a great problem of not getting the CD cache refreshed on publish. I was asked about the wildcard option today. I see from your other post that there’s a 301 redirect module that can handle that. I cannot find it. I also noticed that this module does not work with media items. So we installed a non-sitecore related redirect application to handle the media files, and are using this module for page redirects. The last thing I want to do is add a 3rd redirect module into the mix. Any suggestions?

      Reply
  9. Joseph Esquibel

    Hello, thanks for your hard work.

    I installed the packages in sitecore whenever I select the content editor, I get this error message:

    Redirect Manager SQL Provider: connection string entry not found for ‘RedirectManager’

    Is there something I didn’t install correctly?

    Thanks,
    Jey

    Reply
  10. Abhishek Shrivastava

    I have used this tool on v6.5 and it worked great. I now need same functionality on V7.1.

    What changes need to be done to get this module working for v7.1? Or does anyone have a beta version of this module that could work on v7.0 or greater?

    Thank you.

    Reply
  11. kumaresan

    Hi Paul,

    I am running into a publishing Media item error. Below is the error.can you Please suggestion on this issue
    Job started: Publish to ‘web’|#Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. —> System.ApplicationException: Redirect Manager failed parsing item url generated by linkmanager. Url : ~/media/napocska.ashx ItemId : {B4F98E43-80E2-4247-A775-71A25B3B88D7}, —> System.UriFormatException: Invalid URI: The format of the URI could not be determined.
    at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
    at System.Uri..ctor(String uriString)
    at RedirectManager.Pipelines.PublishItem.Processor.Process(PublishItemContext context)
    — End of inner exception stack trace —
    at RedirectManager.Pipelines.PublishItem.Processor.Process(PublishItemContext context)
    at (Object , Object[] )
    at Sitecore.Pipelines.PipelineMethod.Invoke(Object[] parameters)
    at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
    at Sitecore.Pipelines.CorePipeline.Run(String pipelineName, PipelineArgs args, String pipelineDomain, Boolean failIfNotExists)
    at Sitecore.Pipelines.CorePipeline.Run(String pipelineName, PipelineArgs args, String pipelineDomain)
    at Sitecore.Pipelines.CorePipeline.Run(String pipelineName, PipelineArgs args)
    at Sitecore.Publishing.Pipelines.PublishItem.PublishItemPipeline.Run(PublishItemContext context)
    at Sitecore.Publishing.Pipelines.Publish.ProcessQueue.ProcessEntries(IEnumerable`1 entries, PublishContext context)
    at Sitecore.Publishing.Pipelines.Publish.ProcessQueue.Process(PublishContext context)
    at (Object , Object[] )
    at Sitecore.Pipelines.PipelineMethod.Invoke(Object[] parameters)
    at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
    at Sitecore.Pipelines.CorePipeline.Run(String pipelineName, PipelineArgs args, String pipelineDomain, Boolean failIfNotExists)
    at Sitecore.Pipelines.CorePipeline.Run(String pipelineName, PipelineArgs args, String pipelineDomain)
    at Sitecore.Pipelines.CorePipeline.Run(String pipelineName, PipelineArgs args)
    at Sitecore.Publishing.Pipelines.Publish.PublishPipeline.Run(PublishContext context)
    at Sitecore.Publishing.Publisher.PerformPublish()
    at Sitecore.Publishing.Publisher.Publish()
    — End of inner exception stack trace —
    at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
    at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
    at Sitecore.Reflection.MethodInstance.Invoke()
    at Sitecore.Jobs.JobRunner.RunMethod(JobArgs args)
    at (Object , Object[] )
    at Sitecore.Pipelines.PipelineMethod.Invoke(Object[] parameters)
    at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
    at Sitecore.Pipelines.CorePipeline.Run(String pipelineName, PipelineArgs args, String pipelineDomain, Boolean failIfNotExists)
    at Sitecore.Pipelines.CorePipeline.Run(String pipelineName, PipelineArgs args, String pipelineDomain)
    at Sitecore.Jobs.Job.ThreadEntry(Object state)

    Reply
  12. Pingback: SQL Based Sitecore Redirect Manager (now with QueryStrings!) | Cortex Exodus

Leave a Reply to kumaresan Cancel reply

Your email address will not be published. Required fields are marked *