For a customer I have build a complete new site in Umbraco. It used to be php and some html. All the old pages are gone. However, most of the old links (very bad SEO, all in root) can be mapped to the new pages in umbraco.
This is what i came up with:
Create custsom 404 handler
in the handler coder, check if the url is on the list, then redirect to the new page
This works BUT.... is HAS to be a 301 redirect.
suggestions? Or back to the original idea: re-create all old pages and write a redirect in the files (300+ pages)
You can easily do a 301 redirect from a 404 handler. I'm doing it on my blog that I am moving from wordpress to Umbraco.
Here is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using umbraco;
using System.Xml.Linq;
using System.Web;
namespace MortenBock.Extensions.NotFoundHandlers
{
public class LegacyBlogNotFoundHandler : umbraco.interfaces.INotFoundHandler
{
private int _redirectID = -1;
public bool CacheUrl
{
get { return false; }
}
public bool Execute(string url)
{
//Check if the url matches the old type that ends with .htm
if (url.EndsWith(".htm"))
{
//Try to locate an umbraco page that fits the requested url
XDocument contentDocument = XDocument.Parse(content.Instance.XmlContent.DocumentElement.OuterXml);
var q = from c in contentDocument.Descendants("data")
where (string)c.Attribute("alias").Value == "blogPostLegacyUrl" && (string)c.Value == "/"+url
select c.Parent.Attribute("id");
if (q.Count<XAttribute>() > 0)
{
bool success = int.TryParse(q.ElementAt<XAttribute>(0).Value, out _redirectID);
//If an umbraco page was found, do a 301 redirect
if(success){
HttpContext.Current.Response.Status = "301 Moved Permanently";
HttpContext.Current.Response.AddHeader("Location",umbraco.library.NiceUrl(_redirectID));
}
//If not, rutern false to let the next 404 hander try
return success;
} else {
//If not, rutern false to let the next 404 hander try
return false;
}
}
else
{
return false;
}
}
public int redirectID
{
get { return _redirectID; }
}
}
}
Good approach from Morten, was thinking of setting the status and header on the response object, just wasn't sure if it was the right place here. Apparently it is! Big thumbs up!
If you use the integrated pipeline, the it should be handled by default. There is a web.config on codeplex that lets you set up Umbraco to work under integrated pipeline mode.
It does work on IIS7, and the custom 404handler i wrote does kick in, but only for aspx files, not htm files. So i think i still must set iis up like douglas wrote. But how?
"With integrated pipeline, the ASP.NET functionality is fully integrated into the main request processing in IIS, which means that all ASP.NET features are now available for any type of requests. This effectively eliminates the need for the wildcard handler mapping. Now you can use your existing ASP.NET modules and have them applied to all requests."
Now I have no where near the Umbraco experience as everyone else, so heres two options from me :)
Option 1
Not sure if this helps, but I had the same problem with a custom site I developed. So I created a global.asax file and added the following under Application_Error
void Application_Error(object sender, EventArgs e){ // Code that runs when an unhandled error occurs Exception ex = new Exception(); ex = Server.GetLastError(); if (g.InStr(ex.Message.ToString(), "does not exist") > 0) {
// You can 301 redirect here - I run a couple of methods to redirect to the right page, then fall back on a 301 redirect to the home page
} }
From what I have read this isn't ideal, but it got me out of a whole load of problems - Thought you might be able to play with it and come up with somthing
Options 2
Install ISAPI rewrite (Free version) and then set the redirects in a mapfile?
ok, I got it to work, but not as elegant as i should but i could not let the customer wait any longer.
This is what I did:
I created a custom 404page in Umbraco (just like a normal page). In IIS i have set the 404page to this page. On this page in umbraco I put a .net custom control that checks the url. I have a list of old urls that should be redirected to the new. So I check the list, if it is in the list I do the redirect.
Works, but it is a workaraond. I would rather like to use the umbraco 404 handler mechanism...
Only thing I changed is the connectionstring. Did you go into your IIS manager and select the Integrated Pipeline mode for your app pool? You need to do that to use the web.config file...
Morten, How did you connect your rewrite module to the web.config? I was under the impression that you have to let IIS 7 know about your url rewriting module.
I tried adding <add name="MyUrlRewrite" type="MyNamespace.MyModule.Redirect_Handler, MyNamespace.MyModule" preCondition="" /> inside the <system.webServer> <modules> .. </modules> </system.webServer> tags, but IIS somehow isn't able to find my module.
I even used .net reflector to make sure the right "MyNamespace.MyModule" was present in the dll in my bin folder.. Any ideas on what is to be done? Perhaps i need to add this information inside <system.web> <httpModules>, but I thought that was only for IIS 6.
I did not write a module. I implemented the inotfoundhandler interface from umbraco, and added my class to the /config/404handlers.config file.
If your module is not running, you might want to google a bit for the runallmanagedmodulesforallrequests attribute. It seems to help sometimes, in order to get modules to run for all requests, regardless of extension.
Great suggestion morten. Meanwhile what i ended up doing was to create a branch of the umbraco source, where I modified the requestmodule.cs inside the presentation module. This works well for me.
//first time init, starts timers, and sets httpContext InitializeApplication(app);
// grab the original url before anything modifies it HttpContext httpContext = mApp.Context; httpContext.Items[ORIGINAL_URL_CXT_KEY] = rewrite404Url(httpContext.Request.Url.AbsolutePath, httpContext.Request.Url.Query, false);
// create the Umbraco context UmbracoContext.Current = new UmbracoContext(httpContext); string path = httpContext.Request.Path; string newURL = ""; //return 301 (for google) if URL is old page (info. stored in custom table) if (DBHelper.getURLToRewrite(path.Length > 2 ? path.Substring(1):"", out newURL)) { //perform 301 redirect httpContext.Response.Clear(); httpContext.Response.Status = "301 Moved Permanently"; httpContext.Response.AddHeader("Location", newURL);
301 redirect from non existing url
For a customer I have build a complete new site in Umbraco. It used to be php and some html. All the old pages are gone. However, most of the old links (very bad SEO, all in root) can be mapped to the new pages in umbraco.
This is what i came up with:
This works BUT.... is HAS to be a 301 redirect.
suggestions? Or back to the original idea: re-create all old pages and write a redirect in the files (300+ pages)
Couldn't you do with a http handler and perform a 301 redirect if page url in in list (if that fires before umbraco request handler comes in)?
Hope this helps.
Regards,
/Dirk
how do I do that? I know how to build a httphandler but How do I make it catch the incoming request?
You can easily do a 301 redirect from a 404 handler. I'm doing it on my blog that I am moving from wordpress to Umbraco.
Here is my code:
Good approach from Morten, was thinking of setting the status and header on the response object, just wasn't sure if it was the right place here. Apparently it is! Big thumbs up!
Cheers,
/Dirk
This is great! But now the next problem... How do I catch the htm page in my site? Currently it is handled by IIS.
damn this is not easy to do in IIS7. It keeps handeling the error BEFORE umbraco can :(
Tips?
In IIS you need to set .htm (or set a global handler if you like) to be handled by asp.net, just like a .aspx page would be. That should do it.
cheers,
doug.
If you use the integrated pipeline, the it should be handled by default. There is a web.config on codeplex that lets you set up Umbraco to work under integrated pipeline mode.
If have downloaded the web.config found here: http://umbraco.codeplex.com/SourceControl/changeset/view/48966#742920
It does work on IIS7, and the custom 404handler i wrote does kick in, but only for aspx files, not htm files. So i think i still must set iis up like douglas wrote. But how?
Did you set up your site (and app pool) to use Integrated Pipeline mode?
From: http://learn.iis.net/page.aspx/508/wildcard-script-mapping-and-iis-7-integrated-pipeline/
"With integrated pipeline, the ASP.NET functionality is fully integrated into the main request processing in IIS, which means that all ASP.NET features are now available for any type of requests. This effectively eliminates the need for the wildcard handler mapping. Now you can use your existing ASP.NET modules and have them applied to all requests."
Now I have no where near the Umbraco experience as everyone else, so heres two options from me :)
Option 1
Not sure if this helps, but I had the same problem with a custom site I developed. So I created a global.asax file and added the following under Application_Error
From what I have read this isn't ideal, but it got me out of a whole load of problems - Thought you might be able to play with it and come up with somthing
Options 2
Install ISAPI rewrite (Free version) and then set the redirects in a mapfile?
:)
still having troubles... Morten, could you please share the web.config you used for this?
ok, I got it to work, but not as elegant as i should but i could not let the customer wait any longer.
This is what I did:
I created a custom 404page in Umbraco (just like a normal page). In IIS i have set the 404page to this page. On this page in umbraco I put a .net custom control that checks the url. I have a list of old urls that should be redirected to the new. So I check the list, if it is in the list I do the redirect.
Works, but it is a workaraond. I would rather like to use the umbraco 404 handler mechanism...
so still I would like to see Morten's webconfig
Hi Roland
The web.config I used is the one located here:
http://umbraco.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=23321#DownloadId=70203
Only thing I changed is the connectionstring. Did you go into your IIS manager and select the Integrated Pipeline mode for your app pool? You need to do that to use the web.config file...
Morten, How did you connect your rewrite module to the web.config? I was under the impression that you have to let IIS 7 know about your url rewriting module.
I tried adding <add name="MyUrlRewrite" type="MyNamespace.MyModule.Redirect_Handler, MyNamespace.MyModule" preCondition="" /> inside the <system.webServer> <modules> .. </modules> </system.webServer> tags, but IIS somehow isn't able to find my module.
I even used .net reflector to make sure the right "MyNamespace.MyModule" was present in the dll in my bin folder.. Any ideas on what is to be done? Perhaps i need to add this information inside <system.web> <httpModules>, but I thought that was only for IIS 6.
I did not write a module. I implemented the inotfoundhandler interface from umbraco, and added my class to the /config/404handlers.config file.
If your module is not running, you might want to google a bit for the runallmanagedmodulesforallrequests attribute. It seems to help sometimes, in order to get modules to run for all requests, regardless of extension.
Great suggestion morten. Meanwhile what i ended up doing was to create a branch of the umbraco source, where I modified the requestmodule.cs inside the presentation module. This works well for me.
is working on a reply...