301 Redirect for Media Item

We recently had a requirement about 301 redirect for media item like pdf files. Sitecore Shared Source 301 Redirect module was used for 301 redirect, but it does not support 301 redirect for media item requested url, because sitecore MediaRequestHandler redirect to ItemNotFoundUrl, if requested URL does not exist in sitecore.

CustomMediaRequestHandler allows you to extend the default MediaRequestHandler, so you can easily check if the requested media Url from redirect url module, does not exist in sitecore media library, then get value of “Redirect to Item” or “Redirect to Url”, and redirect web request on these value.

Custom DoRedirect function process if request media is not in sitecore.

Because this configuration is not within the /configuration/sitecore element, this requires one or two updates to the /web.config file itself. Under the /configuration/system.webServer/handlers element:

<!–<add verb=”*” path=”sitecore_media.ashx” type=”Sitecore.Resources.Media.MediaRequestHandler, Sitecore.Kernel” name=”Sitecore.MediaRequestHandler”/>–>
<add verb=”*” path=”sitecore_media.ashx” type=”Project.Framework.CustomMediaRequestHandler, Project.Framework” name=”Sitecore.MediaRequestHandler”/>

public class CustomMediaRequestHandler : MediaRequestHandler
{
protected override bool DoProcessRequest(HttpContext context)
{
Assert.ArgumentNotNull((object)context, “context”);
MediaRequest request = MediaManager.ParseMediaRequest(context.Request);
if (request == null)
return false;
Media media = MediaManager.GetMedia(request.MediaUri);
if (media != null)
return this.DoProcessRequest(context, request, media);
using (new SecurityDisabler())
media = MediaManager.GetMedia(request.MediaUri);
string str;
if (media == null)
{
str = DoRedirect(context) ? string.Empty : Settings.ItemNotFoundUrl;
}
else
{
Assert.IsNotNull((object)Context.Site, “site”);
str = Context.Site.LoginPage != string.Empty ? Context.Site.LoginPage : Settings.NoAccessUrl;
}
if (!string.IsNullOrEmpty(str))
{
if (Settings.RequestErrors.UseServerSideRedirect)
HttpContext.Current.Server.Transfer(str);
else
HttpContext.Current.Response.Redirect(str);
}
return true;
}

private IEnumerable<Item> GetRedirects(Database db, string templateName, string versionedTemplateName, string queryType)
{
IEnumerable<Item> enumerable = (IEnumerable<Item>)null;

string setting = Sitecore.Configuration.Settings.GetSetting(SharedSource.RedirectModule.Constants.Settings.RedirectRootNode);

switch (queryType)
{
case “fast”:
IEnumerable<Item> first = (IEnumerable<Item>)db.SelectItems(string.Format(“fast:{0}//*[@@templatename='{1}']“, (object)setting, (object)templateName));
IEnumerable<Item> source = (IEnumerable<Item>)db.SelectItems(string.Format(“fast:{0}//*[@@templatename='{1}']“, (object)setting, (object)versionedTemplateName));
enumerable = Enumerable.Any<Item>(source, (Func<Item, bool>)(i => i.Versions.Count > 0)) ? Enumerable.Union<Item>(first, Enumerable.Where<Item>(source, (Func<Item, bool>)(i => i.Versions.Count > 0))) : first;
break;
case “query”:
enumerable = (IEnumerable<Item>)db.SelectItems(string.Format(“{0}//*[@@templatename='{1}' or @@templatename='{2}']“, (object)setting, (object)templateName, (object)versionedTemplateName));
break;
default:
Item obj = db.SelectSingleItem(setting);
if (obj != null)
{
enumerable = Enumerable.Where<Item>((IEnumerable<Item>)obj.Axes.GetDescendants(), (Func<Item, bool>)(i => i.TemplateName == templateName || i.TemplateName == versionedTemplateName));
break;
}
else
break;
}
return enumerable ?? (IEnumerable<Item>)new Item[0];
}

protected bool DoRedirect(HttpContext context)
{
string input = HttpContext.Current.Request.Url.ToString();
string absolutePath = HttpContext.Current.Request.Url.AbsolutePath;

Database database = Context.Database;

//bool isRedirectUrl = false;
Item redirectUrlItem = null;
foreach (Item redirectItem in GetRedirects(database, SharedSource.RedirectModule.Constants.Templates.RedirectUrl, SharedSource.RedirectModule.Constants.Templates.VersionedRedirectUrl, Sitecore.Configuration.Settings.GetSetting(SharedSource.RedirectModule.Constants.Settings.QueryExactMatch)))
{
if (input.Equals(redirectItem[SharedSource.RedirectModule.Constants.Fields.RequestedUrl], StringComparison.OrdinalIgnoreCase) ||
absolutePath.Equals(redirectItem[SharedSource.RedirectModule.Constants.Fields.RequestedUrl],
StringComparison.OrdinalIgnoreCase))
{
//isRedirectUrl = true;
redirectUrlItem = redirectItem;
break;
}
}

if (redirectUrlItem != null)
{
context.Response.StatusCode = 301;
if (!string.IsNullOrEmpty(redirectUrlItem[SharedSource.RedirectModule.Constants.Fields.RedirectToItem]))
{

var sitecoreItem = redirectUrlItem[SharedSource.RedirectModule.Constants.Fields.RedirectToItem];
var item = Sitecore.Context.Database.GetItem(sitecoreItem);
//MediaItem mediaItem = item;

var isMediaItem = MediaManager.HasMediaContent(item);

if (isMediaItem)
{
var mediaItemUrl = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority) + MediaManager.GetMediaUrl(item);
context.Response.AddHeader(“Location”, mediaItemUrl);
return true;
}

var redirecturl = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority) + LinkManager.GetItemUrl(item);
context.Response.AddHeader(“Location”, redirecturl);
return true;
}
if (!string.IsNullOrEmpty(redirectUrlItem[SharedSource.RedirectModule.Constants.Fields.RedirectToUrl]))
{
var redirecturl = redirectUrlItem[SharedSource.RedirectModule.Constants.Fields.RedirectToUrl];

context.Response.AddHeader(“Location”, redirecturl);
return true;
}

}

return false;
}
}

This way we can 301 redirect for sitecore media item .

 

WFFM custom save action not woking on CD environment

We configured CM/CD environment for a website. When using Web Forms for Marketers in a CD environment, We faced an issue on custom save action, It was not working, it did not log any error in sitecore logs and it goes to next action like redirect and success page. 

There is a simple and easy way to resolve this issue, on WFFM custom save actions we need to mark checked on “Client Action” option.

ClientAction