Restart the Sitecore Client and Server Using Custom Pipelines
Last week Michael West asked me about creating shortcuts to restart the Sitecore client and server via this tweet, and I was immediately curious myself on what was needed to accomplish this.
If you are unfamiliar with restarting the Sitecore client and server, these are options that are presented to Sitecore users — typically developers — after installing a package into Sitecore:
Until last week, I never understood how either of these checkboxes worked, and uncovered the following code during my research:
Michael West had conveyed how he wished these two lines of code lived in pipelines, and that prompted me to write this article — basically encapsulate the logic above into two custom pipelines: one to restart the Sitecore client, and the other to restart the Sitecore server.
I decided to define the concept of a ‘Restarter’, an object that restarts something — this could be anything — and defined the following interface for such objects:
namespace Sitecore.Sandbox.Utilities.Restarters { public interface IRestarter { void Restart(); } }
I then created the following IRestarter for the Sitecore client:
using Sitecore; using Sitecore.Diagnostics; using Sitecore.Web.UI.Sheer; namespace Sitecore.Sandbox.Utilities.Restarters { public class SitecoreClientRestarter : IRestarter { private ClientResponse ClientResponse { get; set; } public SitecoreClientRestarter() : this(Context.ClientPage) { } public SitecoreClientRestarter(ClientPage clientPage) { SetClientResponse(clientPage); } public SitecoreClientRestarter(ClientResponse clientResponse) { SetClientResponse(clientResponse); } private void SetClientResponse(ClientPage clientPage) { Assert.ArgumentNotNull(clientPage, "clientPage"); SetClientResponse(clientPage.ClientResponse); } private void SetClientResponse(ClientResponse clientResponse) { Assert.ArgumentNotNull(clientResponse, "clientResponse"); ClientResponse = clientResponse; } public void Restart() { ClientResponse.Broadcast(ClientResponse.SetLocation(string.Empty), "Shell"); } } }
The class above has three constructors. One constructor takes an instance of Sitecore.Web.UI.Sheer.ClientResponse — this lives in Sitecore.Kernel.dll — and another constructor takes in an instance of
Sitecore.Web.UI.Sheer.ClientPage — this also lives in Sitecore.Kernel.dll — which contains a property instance of Sitecore.Web.UI.Sheer.ClientResponse, and this instance is set on the ClientResponse property of the SitecoreClientRestarter class.
The third constructor — which is parameterless — calls the constructor that takes in a Sitecore.Web.UI.Sheer.ClientPage instance, and passes the ClientResponse instance set in Sitecore.Context.
I followed building the above class with another IRestarter — one that restarts the Sitecore server:
using Sitecore.Install; namespace Sitecore.Sandbox.Utilities.Restarters { public class SitecoreServerRestarter : IRestarter { public SitecoreServerRestarter() { } public void Restart() { Installer.RestartServer(); } } }
There really isn’t much happening in the class above. It just calls the static method RestartServer() — this method changes the timestamp on the Sitecore instance’s Web.config to trigger a web application restart — on Sitecore.Install.Installer in Sitecore.Kernel.dll.
Now we need to a way to use the IRestarter classes above. I built the following class to serve as a processor of custom pipelines I define later on in this post:
using Sitecore.Diagnostics; using Sitecore.Pipelines; using Sitecore.Sandbox.Utilities.Restarters; namespace Sitecore.Sandbox.Pipelines.RestartRestarter { public class RestartRestarterOperations { private IRestarter Restarter { get; set; } public void Process(PipelineArgs args) { Assert.ArgumentNotNull(args, "args"); Assert.ArgumentNotNull(Restarter, "Restarter"); Restarter.Restart(); } } }
Through a pipeline processor configuration setting, we define the type of IRestarter — it’s magically created by Sitecore when the pipeline processor instance is created.
After some null checks, the Process() method invokes Restart() on the IRestarter instance, ultimately restarting whatever the IRestarter is set to restart.
I then needed a way to test the pipelines I define later on in this post. I built the following class to serve as commands that I added into the Sitecore ribbon:
using Sitecore.Diagnostics; using Sitecore.Pipelines; using Sitecore.Shell.Framework.Commands; namespace Sitecore.Sandbox.Commands.Admin { public class Restart : Command { public override void Execute(CommandContext context) { Assert.ArgumentNotNull(context, "context"); Assert.ArgumentNotNull(context.Parameters, "context.Parameters"); Assert.ArgumentNotNullOrEmpty(context.Parameters["pipeline"], "context.Parameters[\"pipeline\"]"); CorePipeline.Run(context.Parameters["pipeline"], new PipelineArgs()); } } }
The command above expects a pipeline name to be supplied via the Parameters NameValueCollection instance set on the CommandContext instance passed to the Execute method() — I show later on in this post how I pass the name of the pipeline to the command.
If the pipeline name is given, we invoke the pipeline.
I then glued everything together using the following configuration file:
<?xml version="1.0" encoding="utf-8"?> <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <commands> <command name="admin:Restart" type="Sitecore.Sandbox.Commands.Admin.Restart, Sitecore.Sandbox"/> </commands> <pipelines> <restartClient> <processor type="Sitecore.Sandbox.Pipelines.RestartRestarter.RestartRestarterOperations, Sitecore.Sandbox"> <Restarter type="Sitecore.Sandbox.Utilities.Restarters.SitecoreClientRestarter, Sitecore.Sandbox"/> </processor> </restartClient> <restartServer> <processor type="Sitecore.Sandbox.Pipelines.RestartRestarter.RestartRestarterOperations, Sitecore.Sandbox"> <Restarter type="Sitecore.Sandbox.Utilities.Restarters.SitecoreServerRestarter, Sitecore.Sandbox"/> </processor> </restartServer> </pipelines> </sitecore> </configuration>
I’m omitting how I created custom buttons in a custom ribbon in Sitecore to test this. If you want to learn about adding buttons to the Sitecore Ribbon, please read John West’s blog post on doing so.
However, I did do the following to pass the name of the pipeline we want to invoke in the custom command class defined above:
I wish I could show you some screenshots on how this works. However, there really isn’t much visual to see here.
If you have any suggestions on how I could show this in action, or improve the code above, please share in a comment.