Better way of handling sitecore 404 pages
Out of the box Sitecore way of handling 404 error is to respond with 302 redirect the original request to "sitecore/service/notfound.aspx". Then "sitecore/service/notfound.aspx" will respond with 404 response code.
It is not a good way for SEO purposes as crawlers think the page exists. It did not know it is a 404 response.
Sitecore provides a configuration setting not to redirect on an item not found.
<setting name="RequestErrors.UseServerSideRedirect">
<patch:attribute name="value">true</patch:attribute>
</setting>
Changing RequestErrors.UseServerSideRedirect to true will not redirect but with the response with 404 status code.
This helps in some way, but not completely, as in Sitecore we want 404 page to be content manage.
So, on the page not found
- we need to respond with 404.
- Do a server tranfer to sitecore 404 content page.
- reposnds 200 status code of 404 content page.
There is a configuration setting in Sitecore to set 404 content pages in Sitecore:
<setting name="ItemNotFoundUrl">
<patch:attribute name="value">/404</patch:attribute>
</setting>
<setting name="LinkItemNotFoundUrl">
<patch:attribute name="value">/404</patch:attribute>
</setting>
We can set the name of 404 content page here.
Here is how we can achieve this:
- Add a processor after HttpRequest.ItemResolver on HttpRequestBegin pipeline.
- Find if the content item is null if null get 404 content page set as the context item.
- Add another processor in the pipeline httpRequestEnd after EndDiagnostics to set the 404 status code for not found Item.
Adding a processor after HttpRequest.ItemResolver on HttpRequestBegin pipeline
Add code to your patch file
<pipelines>
<httpRequestBegin>
<processor type="sitecoreBlog.tools4geeks.SitecoreCustom.Pipelines.HttpRequest.NotFoundProcessor, sitecoreBlog.tools4geeks.SitecoreCustom"
patch:after="processor[@type='Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel']" />
</httpRequestBegin>
</pipelines>
public class NotFoundProcessor : Sitecore.Pipelines.HttpRequest.HttpRequestProcessor
{
public override void Process(Sitecore.Pipelines.HttpRequest.HttpRequestArgs args)
{
if (Sitecore.Context.Item != null || Sitecore.Context.Site == null || Sitecore.Context.Database == null)
{
return;
}
if (Sitecore.Context.Item == null)
{
var notFoundItem =
Sitecore.Context.Database.GetItem(string.Concat(Sitecore.Context.Site.StartPath,
Settings.ItemNotFoundUrl));
if (notFoundItem != null)
{
CustomContext.Current.PageNotFound = true;
Sitecore.Context.Item = notFoundItem;
}
}
}
}
Inherit your NotFoundProcessor from HttpRequestProcessor and override the process method.
I have created a singleton class called CustomContext to store values on every HTTP request, where I have stored current context request is PageNotFound.
Adding processor in the pipeline httpRequestEnd after EndDiagnostics
Add this to your patch file:
<pipelines>
<httpRequestEnd>
<processor type="sitecoreBlog.tools4geeks.SitecoreCustom.Pipelines.HttpRequest.SetHttpResponseCode, sitecoreBlog.tools4geeks.SitecoreCustom"
patch:after="processor[@type='Sitecore.Pipelines.HttpRequest.EndDiagnostics, Sitecore.Kernel']"/>
</httpRequestEnd>
</pipelines>
public class SetHttpResponseCode : HttpRequestProcessor
{
public override void Process(HttpRequestArgs args)
{
if (CustomContext.Current.PageNotFound)
{
HttpContext.Current.Response.StatusCode = (int) HttpStatusCode.NotFound;
}
}
}
Here we are checking the value we set on HttpRequestBegin Pipeline CustomContext.Current.PageNotFound based on it we are setting response status code to 404.
Let me know if you have any questions. Hope this helps.
Global content sharing strategy for buckets and repositories in sitecore
If you have a global section with a repository of items in Sitecore buckets and are shared between different Sitecore websites in a multi-site environment, here is the way how to deal it in a nicer way.
Let's imagine we have a repository of products in Sitecore buckets, which will be used by multiple websites. If we need to render these products on different websites, there are many ways we can approach this.
- Wildcards and custom code on wildcard page layout to render product details.
- Wildcard pages and making context item as the product item
- using custom item resolver
There are pros and cons in all above cases, the solution I found best is using wildcard pages and making product item as the context item.
It has many advantages, by doing this way we can use Sitecore out of the box personalisation, experience editor works as good as normal website item. The only con is it needs a little bit of customisation.
So let's see how we can do this.
Firstly we need to add a new processor at the end of mvc.getPageItem pipeline like:
<pipelines>
<mvc.getPageItem>
<processor patch:after="processor[@type='Sitecore.Mvc.Pipelines.Response.GetPageItem.GetFromOldContext, Sitecore.Mvc']" type="sitecoreblog.tools4geeks.SitecoreCustom.Pipelines.Response.GetPageItem.GetForWildcardPages, sitecoreblog.tools4geeks.SitecoreCustom"/>
</mvc.getPageItem>
</pipelines>
Second step is to implement the processor.
public class GetForWildcardPages : GetPageItemProcessor
{
Assert.ArgumentNotNull(args, "args");
if (args.Result != null)
{
if (args.Result.TemplateID == new ID(TemplateIds.productWildcard))
{
var path = args.RouteData.Values.FirstOrDefault(x => x.Key == "pathInfo").Value.ToString();
var productId = GetIdFromPath(path);
if (!string.IsNullOrEmpty(productId))
{
var product = GetComposerItem(productId);
if (product == null)
{
//set 404 status code.
}
args.Result = product;
}
}
}
}
I feel this is the cleanest way of using repositories in Sitecore website. Please let me know in comments if you had a better idea.
The other two approaches are not good for personalisation and experienced editor.
Creating a web API in sitecore for ajax calls with in sitecore context
Sometimes we do need to create web APIs for ajax calls in our Sitecore solution.
By doing a normal web API will not initialize Sitecore pipeline, so this makes Sitecore.Context.Site || Sitecore.Context.Database null.
To get the normal Sitecore context we need to add a custom route to route table and add it to Sitecore pipeline.
Steps to follow:
1. Add your custom Route to RouteTable.
2. Add your custom processor at the end of the initialize pipeline.
3. Inherit your custom Sitecore API controller from SitecoreController
Adding custom Route to RouteTable
public class RegisterCustomRoute
{
public virtual void Process(PipelineArgs args)
{
RouteTable.Routes.MapRoute("RouteName", "CustomApi/{controller}/{action}/");
}
}
Add your custom processor at the end of the initialize pipeline
<sitecore>
<pipelines>
<initialize>
<processor patch:after="processor[@type='Sitecore.Pipelines.Loader.EnsureAnonymousUsers, Sitecore.Kernel']" type="sitecoreBlog.tools4geeks.Custom.RegisterCustomRoute, sitecoreBlog.tools4geeks"/>
</initialize>
</pipelines>
</sitecore>
While creating a controller inherit it from SitecoreController.
This is it, now you got fully flexible sitecore API which can be useful for ajax calls with in sitecoreContext.
Dealing with 500 errors in Sitecore 8,7,6
Step 1: Add below to sytem.web section in web.config file :
<system.web>
<customErrors defaultRedirect="~/Error/500.aspx" mode="RemoteOnly" redirectMode="ResponseRewrite">
<error statusCode="500" redirect="~/Error/500.aspx"/>
</customErrors>
</system.web>
Above code deals with asp.net runtime errors. Make sure it is a .aspx extension but not .html as IIS has some issue dealing with .html extensions on 500 errors.
Step 2: Add below to sytem.webServer section in web.config :
<system.webServer>
<httpErrors errorMode="DetailedLocalOnly" existingResponse="Auto">
<remove statusCode="500" subStatusCode="-1"/>
<error statusCode="500" path="~/Error/500.html" responseMode="File"/>
</httpErrors>
</system.webServer>
Above code deals with any IIS errors.
Now add 500.html and 500.aspx to your build according to your project requirements.
Please let me know if u have any questions about this, i will come back as soon as i can.
What is sitecore patching? Why we as sitecore developers need to use it?
Sitecore provides us with an opportunity to better control our config changes to Sitecore instance in the way of patching.
Imagine changing Sitecore config files for your project needs. It's all good until you need to upgrade your Sitecore solution. On upgrade, u need to compare all config files u have changed and merge changes on every config file. This is very time-consuming and confusing.
Patching helps us on upgrade, as we have not touched raw Sitecore config files. Any upgrade is easy.
Now how does patching engine works in Sitecore?
To include any patch file, u need to place that config file in /App_Config/Include folder. Patch rendering engine renders the patches in alphabetical order. So I would suggest adding a folder called zzz_projectName and add your patch files inside it. So there are fewer chances of our patches being override.
I am not going in deep here about how to patch here. But there is a great pdf from Sitecore explaining that - Sitecore Patching Guide
If you want to see the final patch version you can go to - http://hostname/sitecore/admin/showconfig.aspx
Let me know if u have any questions and I am happy to come back as soon as possible.
RECENT POSTS
POPULAR POSTS
CATEGORIES
- sitecore-unicorn
- sitecore-contacts
- sitecore-xdb
- sitecore-handling-500-errors
- sitecore-bug
- sitecore-media-library
- sitecore-content-editor
- sitecore-patch
- personal-opinions
- programming
- sitecore-error
- sitecore-usermanager
- sitecore-languge-settings
- sitecore-content-language
- microsoft-Bot-Framework
- Chatbot-Beginners
- ChatBot-Emulator
- botFramework
- FirstChatBot
- chatbot
- sitecore-customroutes
- sitecore-api
- sitecore-buckets
- sitecore-wildcards
- sitecore-layoutdetails
- sitecore-modals
- sitecore-client
- sitecore-deviceeditor
- sitecore-best-practises
- sitecore-templates
- sitecore
- sitecore-scheduling
- sitecore-autopublish
- sitecore-autopublish
- extension-method
- sitecore-multisite
- sitecore-events
- sitecore-publishing
- sitecore8.1
- Rendering Parameters
- GlassMapper
- Sitecore