Check it out.
Scenario: You have a CSV file with hundreds or thousands redirects to internal/external urls for your Sitecore site and you don't really want to install 301 Redirects Module for Sitecore or do any changes to the Sitecore content tree. You just want to use what is in the CSV file to do your redirects.
Solution: Write a custom pipeline that will act before 404 happens and do a 301 redirect if one is found.
Let's do this
This is how our CSV file looks like. There is only 2 columns, match url and destination url.
Below is sample code for the Process301Redirects pipleline and neccessary config updates.
Process301Redirects
Here is the code for the custom 301 redirect pipeline. This code is expecting csv file "301redirects.csv" in your website root folder. CacheService is caching the csv file with the file dependency which means the file will be cached until it has been updated.
using System;
using System.IO;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Security;
using System.Web.Hosting;
using System.Runtime.Caching;
using Sitecore;
using Sitecore.Security;
using Sitecore.Data;
using Sitecore.Diagnostics;
using Sitecore.Mvc.Pipelines.Response.GetRenderer;
using Sitecore.Mvc.Presentation;
using Sitecore.Apps.Loader.AppService;
namespace Local.Sitecore.Domain.Pipelines
{
public class Process301Redirects
{
private readonly ICacheService _cacheService;
public Process301Redirects(ICacheService cacheService)
{
_cacheService = cacheService;
}
public void Process(Sitecore.Pipelines.PreprocessRequest.PreprocessRequestArgs args)
{
// Location of the 301 redirects file
string filePath = HostingEnvironment.MapPath("~/301redirects.csv");
// if file does not exist stop here
if(!File.Exists(filePath))
{
return;
}
try
{
var rawUrl = args.Context.Request.RawUrl.ToLower();
List<string> excludeIfContains = new List<string>() { ".css", ".js", ".ashx", ".png", ".jpg", ".gif" };
foreach(var val in excludeIfContains)
{
if(rawUrl.ToLower().Contains(val))
{
return;
}
}
// Build a key that we can use to cache the contents in memory against
string cacheKey = "Process301Redirects";
// set cache policy to expire if file is updated
CacheItemPolicy policy = new CacheItemPolicy();
policy.ChangeMonitors.Add(new HostFileChangeMonitor(new List<string> { filePath }));
Dictionary<string, string> urls = _cacheService.GetFromCache<Dictionary<string, string>>(cacheKey, () => ReadCSVFile(filePath), policy);
string redirectUrl = string.Empty;
if (urls.TryGetValue(rawUrl, out redirectUrl))
{
args.Context.Response.RedirectPermanent(redirectUrl, true);
}
}
catch (Exception exc)
{
Sitecore.Diagnostics.Log.Error(string.Format("Cannot process 301 Redirects in {0}", filePath), exc, this);
}
}
/// <summary>
/// Reads the 301redirects.csv file.
/// File contents are stored in the cache with the file dependency (if file is modified, cache is cleared)
/// </summary>
/// <returns></returns>
public Dictionary<string, string> ReadCSVFile(string filePath)
{
Dictionary<string, string> list = new Dictionary<string, string>();
using (StreamReader streamReader = new StreamReader(filePath))
{
while (!streamReader.EndOfStream)
{
var line = streamReader.ReadLine();
// ensure line is not null or empty
if (!string.IsNullOrEmpty(line))
{
var values = line.Split(',');
// confirm length is 2
if (values.Length > 1)
{
var key = values[0].ToLower();
// var val = values[1].ToLower();
var val = values[1];
// avoid duplicate entries and empty values
if (!list.ContainsKey(key) && !string.IsNullOrEmpty(val))
{
list.Add(key, val);
}
}
}
}
}
return list;
}
}
}
Processor config settings
Don't forget to register this pipleline. Here we go.
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<preprocessRequest>
<processor patch:before="processor[@type='Sitecore.Pipelines.PreprocessRequest.IIS404Handler, Sitecore.Kernel']" type="Local.Sitecore.Domain.Pipelines.Process301Redirects, Local.Sitecore.Domain" />
</preprocessRequest>
</pipelines>
</sitecore>
</configuration>
There's it. Please ask any questions in the comments below. Thanks :)