Archive

Archive for August, 2008

Creating and running custom pipelines in Sitecore

August 27, 2008 11 comments

A lot of what happens when you request a page in Sitecore is handled by pipelines. Actually, Sitecore makes extensive use of pipelines all the way from handling page requests, to uploading files and saving items through the UI.

So what is a pipeline? A pipeline is a discrete set of steps, executed in order. It is an architectural design you can employ for certain cases in your applications. If I have a series of tasks which need to be performed to accomplish a task, then a pipeline may be the way to go. A pipeline will execute the steps in order, so I could use a pipeline for my ordered tasks as well as my unordered tasks (as the order doesn’t matter we don’t care that it was executed in order).

So what can we use this for in the real world? Let’s take validation as an example. Let’s say we have a purchase order item. Before it can move through to the “ship it!” step in the workflow the order must pass validation. That validation usually contains many discrete steps such as billable amount is greater than 0, date is in the past, GST or other taxes have been calculated properly, etc. Each of these discrete steps can be handled in isolation by a separate method or class.

Sitecore uses a pipeline to generate and populate the Sitecore.Context class. This class contains information about the current user, the current site, the current item being requested, etc. Each step in the httpRequestBegin pipeline populates just a single item in the context. The Sitecore pipelines also allow passing of an object through each step. This object can be manipulated by any of the steps and passed through to the next step until the end is reached and the object can be used by whatever executed the pipeline in the first place.

I get many benefits from using a pipeline architecture, the most relevant of which are:

  • Testability: Each step in the pipeline is usually very small and performs only a single task. This makes it much easier to test each smaller piece and pinpoint bugs rather than testing a big composite piece which might perform many steps in a single method and require more debugging to work through the bugs.
  • Recomposition: Pipelines are generally configurable. The pipeline architecture employed by Sitecore allows us to define the pipeline in web.config. The pipeline definition includes what each step is, and the order of those steps. We could also reuse those steps in another pipeline.

So let’s create our own custom pipeline using the Sitecore pipeline architecture. This example pipeline is going to check that an item is valid and passes a set of validation rules implemented in code. (This is just a demo. Please refer to Alexey Rusakov’s awesome validation rules blog posts for how to properly do validation in Sitecore 6). All pipelines in Sitecore require the method being invoked to accept a subclass of Sitecore.Pipelines.PipelineArgs. So we will start by defining our own subclass of the PipelineArgs class that will hold relevant information for our pipeline and allow passing of that data from step to step.

using Sitecore.Data.Items;
using Sitecore.Pipelines;

namespace CustomPipeline
{
  public class CustomPipelineArgs : PipelineArgs
  {
    private bool m_valid = false;
    private string m_message = string.Empty;
    private Item m_item = null;

    public bool Valid
    {
      get { return m_valid; }
      set { m_valid = value; }
    }

    public string Message
    {
      get { return m_message; }
      set { m_message = value; }
    }

    public Item Item
    {
      get { return m_item; }
      set { m_item = value; }
    }

    public CustomPipelineArgs(Item item)
    {
      m_item = item;
    }
  }
}

Each step in the pipeline is called a “processor”. We need to make sure that each processor can accept the args we defined above. The easiest way to do this is to either use an base class or an interface. I’ll go with an interface here because a base class would not be providing any functionality.

namespace CustomPipeline
{
  interface ICustomPipelineProcessor
  {
    void Process(CustomPipelineArgs args);
  }
}

This interface locks each processor into defining the “Process” method which will be called from the pipeline. Next we define each processor class and fill in the Process method to perform it’s specific function. In this example I’ll provide 2 processors.

namespace CustomPipeline
{
  public class DateSet : ICustomPipelineProcessor
  {
    public void Process(CustomPipelineArgs args)
    {
      if (args.Item["date"] == string.Empty)
      {
        args.Valid = false;
        args.Message = "Date has not been set";
      }
    }
  }

  public class TextSet : ICustomPipelineProcessor
  {
    public void Process(CustomPipelineArgs args)
    {
      if (args.Item["text"] == string.Empty)
      {
        args.Valid = false;
        args.Message = "Text has not been set";
      }
    }
  }
}

The DateSet class checks to make sure the date field of the item is not empty and the TextSet class checks to make sure the text field isn’t empty.

Now that we have all the pieces of our pipeline defined we need to create the pipeline in web.config. Open up web.config and find the “pipelines” element. Add a new element before the closing tag containing the XML below.

<CustomPipeline>
  <processor type="CustomPipeline.DateSet, CustomPipeline" />
  <processor type="CustomPipeline.TextSet, CustomPipeline"/>
</CustomPipeline>

We don’t need to define the Process method in the above processor elements as that is the name of the default method the pipeline processor will try to call. We can of course override that method by providing the method to call in the processor tag.

Now all we have to do is invoke the pipeline from somewhere in our code to run the validation over a given item. We need to create the CustomPipelineArgs object, populate it, then call into Sitecore to run our pipeline and pass in the arguments.

CustomPipelineArgs pipelineArgs = new CustomPipelineArgs(item);
CorePipeline.Run("CustomPipeline", pipelineArgs);
if (!pipelineArgs.Valid && !string.IsNullOrEmpty(pipelineArgs.Message))
{
  // Execute code here to deal with failed validation
}

So with just a few lines of code and configuration we can start to reap the benefits of a pipeline architecture for performing our applications processes, leveraging the Sitecore pipeline processor.

Categories: Sitecore

Windows Command Bindings for Revolver

So, you may have guessed that I lean towards the *nix way of doing things with the command bindings in Revolver. I prefer ls over dir. But if you’re writing code for Sitecore you’re definatly working in a Windows environment and probably not so comfortable with the *nix commands.

I’ve written Revolver to be extensible and also to allow the rebinding of the core commands to different monikers. This allows the user to bind the commands to whatever they want. Maybe I want a more verbose command name like listchildren instead of ls or dir. Or maybe I want a really short command name like “l”.

So for those of us that are more comfortable with the Windows world of things, here is a short script to rebind the core commands to Windows equivalents in Revolver.

bind List dir
bind CopyItem copy
bind MoveItem move
bind CreateItem create
bind DeleteItem delete
bind PurgeVersions purge
bind JobManager jobs
bind CopyItemToLanguage copylang

So what do I do with this script? Copy it to your clipboard then open the core database of your Sitecore system. Open the content editor and navigate to /sitecore/system/modules/revolver/scripts/startup and create a new script item. Paste the above script contents into the “script” field. Now if you’d like this script to be executed upon startup so all your sessions use the above monikers, then navigate to /sitecore/system/modules/revolver/startup and create a new “user script” item which you can use to map this script to a particular user or role to execute on startup. Just make sure to add the users and roles with the domain in the format <domain>/<user> or <domain>/<role>.

Categories: Revolver, Sitecore

Sitecore as a Content Delivery Platform

Sitecore does a really good job of separating content from presentation. And a side effect of this is that we can reuse either part in other ways. We can reuse the content section of Sitecore to author and deliver content to different applications and we can reuse the presentation to generate markup for data which lives outside of Sitecore. This post is going to focus on the content side of things.

Sitecore has some great content creation and approval tools. We can define custom entities through data templates. Given enough training, even a technically minded business analyst could create these entities using the template manager. These entities, once created can be placed in workflow, all of which is security enabled, so the proper authorities must approve the content before it is eligible to be published and used by applications and websites. We can also impose restrictions on the data so it will expire at a given date and time.

I’ve heard previously of developers using Sharepoint as the “backend” to their custom written application. And I suppose if you look at it, it makes sense (for a line of business app anyway). Using this kind of platform as the backend means I don’t have to worry about creating a separate administration application to manage the data which the front end application uses. No more CRUD screens to implement. And the security model is already present as well. We can do the exact same thing using Sitecore.

Sitecore allows us complete control over the markup we generate. The markup doesn’t even have to be HTML. It could be XML or CSS or XAML or RSS or anything we like. So after the content has been created in Sitecore, we can have the presentation generate some kind of usable information exchange format. Or, we could expose the content through web services to our application and bypass the presentation components of Sitecore. The content still has to go through the proper reviews such as workflow and publishing, and then our front end application can access the data.

So in our content tree we can create a folder under /sitecore/content/ which holds our applications data. Let’s say it’s tax table data. I can have a “tax entry” template and when the data folder’s URL is hit the presentation I’ve attached to that item will generate the appropriate XML for the client application, which could be written in anything at all.

The most common application I’ve seen this kind of architecture with is Adobe Flash or Microsoft Silverlight. These applications usually make up a part of a web page (if not the entire web page) of a website and they either pull or are fed the data they require from Sitecore. But there is no reason why we couldn’t employ the same techniques to our internal line of business applications as well.

I mentioned above that we can have the presentation generate XAML which could be used to drive our Silverlight applications. XAML is just text, so it’s easy to generate. Normally we don’t want our application UI generated based on content unless we have a very dynamic application. Given the appropriate templates and content structure, and provided the client application was implemented in the correct fashion, we could actually generate completely new “pages” or screens in the application. This item contains an item based on the reports template? OK then, we’ll generate a reports button in the XAML for that screen which opens the report screen with the data from the current item. And the XAML can do all of that for us.

Categories: Sitecore

XML serialization of read only properties

August 7, 2008 1 comment

I was writing a service the other day where I wanted to marshal a custom class across the service boundary. This scenario starts off as a web service (no WCF here…at least not yet anyway). Now it’s quite easy to marshal your own custom class across the web service server to the client…or so you would think. You end up with a class which looks like your class; it has the same properties, but the class is actually completely different. It is just a proxy which was generated from the WSDL your server handed out to your client when you queried it.

This is the work of the wsdl.exe tool which ships with .net (or it is VS?). This tool is used by Visual Studio to create a proxy class for your web service. The problem I was faced with was that I had business logic coded into the entity class which I was trying to return out of the web service call. I also had a few read only properties. I referenced the assembly containing the class in question, but still the wsdl tool created me a proxy. And it’s quite understandable why. If you look at the wsdl (just append ?wsdl to your asmx url) you’ll notice there is no reference to your type’s fully qualified name (such as MyNamespace.MyClass). So it’s no wonder the wsdl tool creates a separate proxy item for you.

The only real way to get your class back into the mix is to hack the generated code which is now included in your solution. Make sure the “Show all Files” option is active in your solution explorer in visual studio, then expand out the “web references” folder, then the service in question, then the Reference.map file under than. There, you’ll find the Reference.cs file which contains the proxy class. If you look at the code in there, you’ll find the proxy method with a return type of your custom class. All you have to do is change this return type and casted return object to use the real referenced class instead of the proxy one. Of course if you ever refresh your web reference you’ll have to change this code again :( .

[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/HelloCustomClass",
  RequestNamespace="http://tempuri.org/",
  ResponseNamespace="http://tempuri.org/",
  Use=System.Web.Services.Description.SoapBindingUse.Literal,
  ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public CustClass HelloCustomClass()
{
  object[] results = this.Invoke("HelloCustomClass", new object[0]);
  return ((CustClass)(results[0]));
}

So in the above code snippet I would change the CustClass type to use my CustClass defined in my assembly and not the proxy generated class.

If you’re going to be calling the web service asynchronously, you’ll also have to update the return type of the Result property of the <Method>CompletedEventArgs where <Method> is the name of your proxy method.

Now that we’ve got our custom class being used we face the next problem; read only properties. By default web services will use the XML formatter to serialize your object for transport over SOAP. The XML formatter doesn’t process any internal members of your class. It uses the public property getters to take a snapshot of the data and the public setters to restore the data at the other end. The problem is, if you have a read only property the formatter will skip it cause it won’t be able to restore it on the other side. To get around this limitation you can implement the IXmlSerializable interface and implement the WriteXml and ReadXml methods to give you total control over how your object is serialized into XML.

But I only want to transport my object through SOAP so I can use it on the other side. I don’t really care how it goes across the wire and I won’t be interoperating with other technologies (.net only). Do I really have to serialize my object nicely (with property values as XML)?? If all you’re concerned with is getting your object where you need it, welcome the binary formatter. But we’re on the web right? Don’t we have to be some variant of XML? No, but just to keep you happy, welcome the binary formatter and base 64 encoded strings (there…you happy now?). But keep in mind that you don’t actually have to use base 64 encoding, and this is one of the reasons some people prefer to handle serialization themselves.

The binary formatter will process the internal members of your class and produce a byte array. We can then take that byte array and base 64 encode it into a string which will transport over HTTP quite nicely. At the other end it’s just a matter of creating a new object from your deserialized binary data. For the binary formatter to serialize your custom class, the class must be marked as serializable using the Serializable attribute.

Serialization is the easy part:

public void WriteXml(XmlWriter writer)
{
  // Create stream to store data from binary formatter in
  MemoryStream stream = new MemoryStream();

  // Serialize the object onto the stream
  BinaryFormatter bf = new BinaryFormatter();
  bf.Serialize(stream, this);

  // Reset the stream so we can write the data to the XML writer
  stream.Seek(0, SeekOrigin.Begin);

  // Write the data as base 64 encoded
  writer.WriteElementString("CustClass", System.Convert.ToBase64String(stream.GetBuffer()));
}

Did I say the binary formatter output a byte array? Yeah it does, but it wants to push it onto a stream. Now we have the serialized data which constitutes our class instance sitting in an element in the XML called CustClass.

Deserialization is a bit funny. After deserialization we are left with an instance of CustClass inside the ReadXml method of the instance we wish to rehydrate. So we can pull the private members out of the deserialized instance and populate our current instance.

public void ReadXml(XmlReader reader)
{
  if(reader.Read())
  {
    // Get data from XML
    byte[] data = System.Convert.FromBase64String(reader.ReadString());

    // Create stream to store the data in for the binary formatter    
    MemoryStream stream = new MemoryStream();
    stream.Write(data, 0, data.Length);

    // Reset to start of stream so binary formatter can read data
    stream.Seek(0, SeekOrigin.Begin);

    // Deserialize the object data into an object
    BinaryFormatter bf = new BinaryFormatter();
    CustClass stored = (CustClass)bf.Deserialize(stream);

    // Populate internal members
    this.m_name = stored.m_name;
    this.m_privateVal = stored.PrivateVal;
    this.m_value = stored.m_value;
  }
}

Keep in mind that by implementing IXmlSerializable we are supposed to push all our private members into the XML as plain XML. The method described here is quicker if we have a lot of private members which need to be serialized. This method also protects us from class implementation changes which alter the internal members except where the name of the internal members changes and we have to update the ReadXml method.

The IXmlSerializable interface defines 3 methods. We have provided implementation for 2 of them so far. The last remaining method is GetSchema(). This method is called when the wdsl is generated (like above where you appended ?wsdl to the asmx url). If we’re not trying to discover the web service or add a web reference to any other projects, we can get away with not implementing this method. We could also just return null from this method and the WSDL generated will tell clients the custom class element in the SOAP message is “anything”. Otherwise you’ll have to output the schema.

Categories: .net
Follow

Get every new post delivered to your Inbox.