5 April 2014

Create your own pipeline


Here is a topic I wanted to post about as I loved the Pipeline concept. In sitecore, the pipeline is a succession of processors which gets executed in the order defined. Each rocessor is doing a specific action. If the processor encounter an error or do not validate whatever condition you want then you can abort the pipeline and exit.

The pipelines in sitecore are great so we can inject processors that can do any action. So if you want to intercept the HttpRequest, you can use the HttpRequestBegin pipeline and inject your own Item resolver or Language resolver...

Now this post is not intended to show you how to use the existing pipeline, as I am sure you would already have done a few custom processor. The idea I wanted to show here is how you could create a pipeline for your own code.

1- Create a config file for your pipeline

your configuration file will start by defining your Custom Pipeline with the different processor:


  
    
      
        
        
      
    
  



2- Classes for your pipeline processor.
When you have multiple processors, please separate your classes in different files. :)
The first processor will: Check for any .update files in a folder and install them into Sitecore:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sitecore.Update.Installer;
using Sitecore.Update.Installer.Exceptions;
using Sitecore.Update.Installer.Installer.Utils;
using Sitecore.Update.Installer.Utils;
using Sitecore.Update.Utils;
using System.IO;
using System.Linq;
using System.Web;
using SC = Sitecore;
using Sitecore.SecurityModel;
using Sitecore.Data.Proxies;
using Sitecore.Data.Engines;
using log4net;
using Sitecore.Update;
using MyProject.Business.Sitecore.Pipelines;

namespace MyProject.Business.Sitecore.Pipelines
{
    public class InstallPackages
    {
        public void Process(MyPipelineArgs args)
        {
            args.NeedToPublish = Install();
        }

        private bool Install()
        {
            var files = Directory.GetFiles(SC.MainUtil.MapPath("/sitecore/admin/Automated_Packages"), "*.update", SearchOption.AllDirectories);
            SC.Context.SetActiveSite("shell");

            bool needToPublish = false;

            using (new SecurityDisabler())
            {
                using (new ProxyDisabler())
                {
                    using (new SyncOperationContext())
                    {
                        foreach (var file in files)
                        {
                            needToPublish = true;
                            try
                            {
                                Install(file);
                                SC.Diagnostics.Log.Info("Automated Deployment success for file " + file, this);

                                File.Delete(file);
                            }
                            catch (Exception ex)
                            {
                                SC.Diagnostics.Log.Error("Automated Deployment error " + ex.StackTrace, this);
                            }
                        }
                    }
                }
            }

            return needToPublish;
        }

        protected string Install(string package){}...
    }
}


The second processor will publish items: Templates, layouts, renderings:
using Sitecore.Data;
using Sitecore.Data.Managers;
using Sitecore.Publishing;
using Sitecore.SecurityModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SC = Sitecore;

namespace MyProject.Business.Sitecore.Pipelines
{
    public class PublishAfterInstall
    {
        public void Process(MyPipelineArgs args)
        {
            if(args.NeedToPublish)
                args.Result = Publish();
        }

        private string Publish()
        {

            string message = string.Empty;

            SC.Context.SetActiveSite("shell");
            using (new SecurityDisabler())
            {
                DateTime publishDate = DateTime.Now;
                SC.Data.Database master = SC.Configuration.Factory.GetDatabase("master");
                SC.Data.Database web = SC.Configuration.Factory.GetDatabase("web");

                // publish specific section - Need to  put those in settings
                ID templateFolderID = new ID("{3C1715FE-6A13-4FCF-845F-DE308BA9741D}");
                ID layoutFolderID = new ID("{EB2E4FFD-2761-4653-B052-26A64D385227}");
                ID systemFolderID = new ID("{13D6D6C6-C50B-4BBD-B331-2B04F1A58F21}");

                try
                {
                    PublishManager.PublishItem(master.GetItem(templateFolderID), new Database[] { web }, LanguageManager.GetLanguages(master).ToArray(), true, false);
                    PublishManager.PublishItem(master.GetItem(layoutFolderID), new Database[] { web }, LanguageManager.GetLanguages(master).ToArray(), true, false);
                    PublishManager.PublishItem(master.GetItem(systemFolderID), new Database[] { web }, LanguageManager.GetLanguages(master).ToArray(), true, false);

                    message = "Success!!!";
                }
                catch (Exception ex)
                {
                    SC.Diagnostics.Log.Info("Publishing failed", this);
                    message = "Failed!!!";
                }

                return message;
            }
        }
    }
}


3- Arguments

Now the question you all have is: well this is great, you will have a succession of processors but how do you pass data from one to the other? Well, as yo may have noticed, the process method for the processors are using a custom Argument which is passed from one processor to the next one!!!! So lets code this custom class as well.
using Sitecore.Pipelines;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyProject.Business.Sitecore.Pipelines
{
    public class MyPipelineArgs : PipelineArgs
    {
        public bool NeedToPublish { get; set; }
        public string Result { get; set; }
    }
}

4- Execute the pipeline from code
To trigger the pipeline, I just created an aspx in the solution so I can go to the URL and debug...
using MyProject.Business.Sitecore.Pipelines;
using Sitecore.Diagnostics;
using Sitecore.Pipelines;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace MyProject.sitecore_modules.MyProject
{
    public partial class InstallPackages : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // Initialise your Arguments
            var pipelineArgs = new MyPipelineArgs();

            // Execute your pipeline, passing your custom argument
            CorePipeline.Run("MyPipeline", pipelineArgs);

            // After the package installer ran and published the site you can log the results
            Log.Info(pipelineArgs.Result, this);
        }
    }
}

Quick last note: since this is an aspx, you could setup the schedul agent to trigger this aspx once a day or more to automate package installation...

1 comment: