Blog
Sitecore Alias as Redirect

Sitecore Alias as Redirect

One feature of Sitecore that I have always disliked is Alias's. On each page of a site, content editors have the ability to click an alias button on the presentation tab and add alternative urls for the page.

Once added these will appear in the Aliases folder under system.

However all this accomplishes is multiple URLs existing for one page which is a big SEO no no.

Content editors like to do this in order to create simple URLs for things like landing pages. e.g. himynameistim.com/Sitecore but search engines hate it as they see multiple pages with the exact same content. As a result the value of each page gets lowered and appears lower in search engine results. What Content editors really want is to set up a 301 redirect so that they can have the simple URL but redirect users to the actual page on the site.

Aliases as Redirects

One solution is to updated the aliases functionality to cause a redirect to it's linked item rather than resolve the page.

To do this we need to create a pipeline processor that inherits from AliasResolver.

1using Sitecore; using Sitecore.Configuration; using Sitecore.Diagnostics; using Sitecore.Pipelines.HttpRequest; using System.Net; using System.Web; using AliasResolver = Sitecore.Pipelines.HttpRequest.AliasResolver; namespace HiMyNameIsTim.Pipelines { public class AliasAsRedirectResolver : AliasResolver { public override void Process(HttpRequestArgs args) { if (!Settings.AliasesActive) { return; // if aliases aren't active, we really shouldn't confuse whoever turned them off } var database = Context.Database; if (database == null) { return; // similarly, if we don't have a database, we probably shouldn't try to do anything } if (!Context.Database.Aliases.Exists(args.LocalPath)) { return; // alias doesn't exist } var targetID = Context.Database.Aliases.GetTargetID(args.LocalPath); // sanity checks for the item if (targetID.IsNull) { Tracer.Error("An alias for \"" + args.LocalPath + "\" exists, but points to a non-existing item."); return; } var item = args.GetItem(targetID); if (database.Aliases.Exists(args.LocalPath) && item != null) { if (Context.Item == null) { Context.Item = item; Tracer.Info(string.Concat("Using alias for \"", args.LocalPath, "\" which points to \"", item.ID, "\"")); } HttpContext.Current.Response.RedirectLocation = item.Paths.FullPath.ToLower() .Replace(Context.Site.StartPath.ToLower(), string.Empty); HttpContext.Current.Response.StatusCode = (int)HttpStatusCode.MovedPermanently; HttpContext.Current.Response.StatusDescription = "301 Moved Permanently"; HttpContext.Current.Response.End(); } } } }

And patch in in place of the regular Alias Resolver.

1<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
2<sitecore> <pipelines>
3<httpRequestBegin> <processor type="HiMyNameIsTim.Core.Pipelines.AliasAsRedirectResolver, LabSitecore.Core" patch:instead="*[@type='Sitecore.Pipelines.HttpRequest.AliasResolver, Sitecore.Kernel']"/> </httpRequestBegin>
4</pipelines> </sitecore>
5</configuration>

The above code is adapted from a solution given by Jordan Robinson but with a bug fixed to stop every valid URL without an alias writing an error to the log file.

Using compile options for version compatibility

Using compile options for version compatibility

Here's the scenario; Your building a module and it needs to be compatible with different versions of a platform. e.g. Sitecore, and everything's great up until the day you need to call different methods in different versions of the platform. You'd rather not drop support for the old versions, and nor do you want to start maintaining two code bases. So what do you do?

C# Preprocessor Directives

Preprocessor directives provide a way to give the compiler instructions to follow while its compiling a project. By using this we can give the compiler conditions to compile different versions in different ways. Thereby allowing us to maintain one codebase, but produce compilations for different versions of the platform. e.g. One for Sitecore 8.0 and another for Sitecore 9.0.

#if, #else and #endif

When the compiler encounters an #if followed by an #endif, it will only compile the code between the two if the specified symbol had been defined.

1#if DEBUG
2 Console.WriteLine("Debug version");
3#else
4 Console.WriteLine("Non Debug version");
5#endif
6

Defining a preprocessor symbol

For the if statement to work, your going to need to define your symbol which is being evaluate.

This can be included in code as follows

1#define YOURSYMBOL

A more useful was of defining this however is to include it in your call to MSBuild (this is particularly useful when using a build server).

1-define:name[;name2]

If your compiling from Visual Studio an easier solution is to set up a new build configuration with a conditional compilation symbol.

  • Right click your solution item in Solution Explorer and select Properties
  • Click Configuration Properties on the left and then Configuration Manager on the right
  • In the pop up window click the Active solution configuration drop down and then click New
  • Enter the name of the build config. In my example above I have SC82 for Sitecore 8.2 and SC90 for Sitecore 9.0.
  • Click Ok and close all the windows you just opened
  • Right click the project that your going to build and select Properties
  • Select the Build tab
  • Select your build configuration from the configuration at the top
  • Enter the symbol your using for the #if directives

Reference different versions of an assembly

Adding conditions to our code is good, but for this to fully work we also need to reference different versions of the assemblies that are causing the issue in the first place.

There's no way of doing this through Visual Studio but by editing the .csproj file manually we can update the hint path on a reference to include the configuration name as a variable.

1..\libraries\$(Configuration)\Sitecore.Kernel.dll False

This example shows how different versions of the Sitecore Kernel can be referenced by keeping each version in a subfolder that corresponds with the build configuration name.

As well as different versions of assemblies, it may also be needed to target different versions of the .NET framework. This can be done in the .csproj file by including additional property groups that have a condition on the configuration name.

1bin\SC82\
2TRACE;SC82
3true
4v4.5.2
5
6bin\SC90\
7TRACE;SC90
8true
9v4.6.2

In this example I'm targeting .net 4.5.2 for my Sitecore 8.2 configuration and 4.6.2 for my Sitecore 9 configuration.

Useful Links

C# preprocessor directives
-define (C# Compiler Options)

Adding Build Statuses to Pull Requests with TeamCity and GitHub

Adding Build Statuses to Pull Requests with TeamCity and GitHub

I'm always looking for ways to improve our build server setup and improve our overall efficiency. So a recent change I've made is to get Team City to start building pull requests and pushing the resulting status back to GitHub.

This improves our dev flow by eliminating the need to do any testing on a pull request if we can already see it will fail a build. Previously someone doing a code review would only find out once they've checked out the change and built it locally, or even worse after approving the request and then breaking the build.

What's particularly good with this setup, is it's testing the resulting merge rather than just the branch being merged in.

Team City Setup

As this is covering a different scenario to our normal build processes which are focused on preparing a build version to be deployed, I set this up as a second build configuration on our projects.

Version Control Settings Root (VCS Root)

The VCS Root needs to be configured to fetch each pull request that is creating in GitHub. To do this, you will need to add a Branch specification which will tell Team City to monitor additional branches rather than just the default branch specified.

I'm using the branch specification +:refs/pull/(*/merge) .

This syntax is telling Team City to monitor references to pull for pull request, the * refers to any pull request, and the merge indicates that we only want to resulting merge of the pull request.

When you create a pull request in GitHub, this merge reference is automatically created for what the resulting merge would look like.

In the projects list, builds will now get labels indicating what they were for:

Build Steps

I created my build configurations by duplicating the existing ones we have that take care of creating builds to be passed onto Octopus Deploy for release. If you do this, it's important to remember to disable all the steps you no longer need.

The less steps you have the quicker your build will run and the quicker the pull request will be updated with a status. Ideally you want the process to finish before someone starts doing a code review! Steps like running Inspections may prove counter productive if the builds are never finished on time.

Triggers

Having a build running automatically for your releases can be a drain on server resources, particularly if you never have any intention of actually doing a deploy for most of them. For this reason our builds are set to manual.

However for statuses to be of any use, they're going to need to be running automatically so that the status is ready for the code reviewer, so we need to add a VCS Trigger.

Build Features

To get Team City to start posting status updates back to GitHub we need to add a build feature. If your on a version of TeamCity prior between 7.1 and 10 then there is a plugin you can grab here https://github.com/jonnyzzz/TeamCity.GitHub. If your on a newer version of TeamCity. i.e. 10+ then the build feature is now built in and is called Commit status publisher. The built in version also has support for Bitbucket, Gerrit, GitLab, JetBrains Upsource and Visual Studio Team Services.

Add the build feature and fill in the config settings.

And that's it. Your pull requests will now automatically build and have the status sent back to GitHub.

Not only will you be able to see this status in GitHub, you'll also be able to click a details link to see the build. Useful in the event that it's failed and you want to see why.

A first look at Sitecore SPEAK 3

A first look at Sitecore SPEAK 3

SPEAK (Sitecore Process Enablement and Accelerator Kit) is the framework for constructing admin interfaces in Sitecore. It was introduced to the platform prior to Sitecore 8, but really became the way to do things after Sitecore 8's UI refresh which introduced the start page and made accessing full page SPEAK applications logical.

SPEAK 1 and 2

The goals of SPEAK were to:

  • Provide a streamlined approach to application development.
  • Enable reuse of UI elements.
  • Enforce a consistent look and feel.

In order to achieve this SPEAK 1 and 2 provides a component library of controls that can be used to construct pages. This ensures that the UI retains a consistent look and feel, and also minimizes the amount of work on a Sitecore developer. Logic is then added to an application using JavaScript for the front end and C# for server side code.

While this all sounds great many developers find SPEAK hard to use. In order to construct a UI out of the re-usable components, Sitecore lent on it's existing functionality to be able to construct pages out of presentation items, however there is no WYSIWYG editor and the only real way to construct the layout is through Sitecore Rocks. This in itself isn't awful, but when combined with the fact the average Sitecore developer doesn't need to build an admin application that often, it presents a steep learning curve using a tool they may not use to put together components they're not familiar with.

SPEAK 3

SPEAK 3 aims to address complaints in previous versions by introducing a completely new framework based on Angular.

Since SPEAKs initial incarnation, client side application development has moved on a long way, so rather than continuing to construct their own framework, Sitecore has chosen Angular as the the platform to use going forward.

Begin Angular, SPEAK 3 applications can run independently of Sitecore, however the purpose of SPEAK 3 is still to make it simple to integrate Sitecore-branded applications into the content manager.

My First Look

Before being a Sitecore back-end developer I worked on bespoke web based applications using client side frameworks such as Knockout, so the news that Sitecore was going to adopt Angular was great. Digging into Angular again however has given me a first hand experience of how fast the JavaScript world is changing. Gone is the promotion of MVC on the client being replaced with service/controller patterns. Whereas with Knockout and AngularJS (what Angular 1.x is now known as) we could add data binding to just an aspect of a page, Angular is really for running an entire application, routing and all.

Building an SPEAK 3 application really means building an Angular application with some modules provided by Sitecore. These modules will provide integration features such as:

  • Sitecore context
  • Translations for applications
  • Translations for the SPEAK 3 component library
  • Component user access authorization
  • Preventing cross-site request forgery (Anti-CSRF)

In addition to this the SPEAK 3 components will also sort out compatibility issues such as modifying the routing so that the application no longer needs to be in the route of the site and can be in a sub-folder of Sitecore.

Angular for a Sitecore dev

To start it's good to know an outline of what developing Angular involves.

Angular 2+ is built using TypeScript. You don't need to use TypeScript, but as most of the examples are you probably will want to too. TypeScript is a superset of of JavaScript which adds strong typing support as well as other features of ECMAScript 2015 to backport it to older versions of JavaScript.

TypeScript needs to be compiled into JavaScript before it can run in the browser.

The easiest way to get started with Angular and TypeScript is using Node.js to install tools via NPM. Node is not a requirement for Angular and you won't need it in production, but for local dev using Node to host your application can make life a lot easier.

Angular has a CLI which makes things easy to create and run an Angular application.

Visual Studio can be used as an IDE for TypeScript and Angular, but you might find life easier using Visual Studio Code.

It's better than it sounds :)

All this might sound a bit daunting to the average C# developer. Technologies like Node and NPM traditionally are more at home in the open source community.

There is however a lot to be positive about. If your the type of dev that prefers writing c# to JavaScript, then the inclusion of TypeScript is going to please you, as it brings the type checking structure and class organisation that we're used too.

The angular cli (command line interface) is also a reason to be pleased. One large difference between the .net and open source world has been the ability to click a button and get going. Open source typically comes with the setup of many components to get a solution working. At times when you try to learn something it can feel like your spending more effort doing setup that actual dev on the platform. Angular still needs to have all these components put together, but the cli takes care of all this for you, effectively recreating a file new project experience, just through a command line.