Belangrijke mededeling over deze pagina:

Deze pagina is niet beschikbaar in het Nederlands en daarom wordt de Engelse versie van het artikel getoond. Dit komt vooral voor bij technische artikelen.

Sitecore uses one configuration per instance with no way of isolating configuration per site.
This means that every pipeline processor, event handler, hook and setting applies to everything within that instance.

When I implement custom pipeline processors (or events), I like to isolate them so they are executed only for specific sites.
I've written an abstract class that I can use on all my pipeline processors to implement support for this type of isolation.

As an example, I've used the ItemLanguageVersionValidator that forces Sitecore to return an "item not found" code when the requested item does not exist in the current context language.
This processor only needs to run for specific sites in my instance.

UPDATE: There is a better way of configuring the list of allowed sites, but I didn't figure that out until after this post was published. Make sure to read the follow up post about Configurable pipeline processors and event handlers!

Configuration

The configuration for this processor looks like this:

<httpRequestBegin>
  <processor type="ParTech.Pipelines.HttpRequestBegin.ItemVersionValidator, ParTech"
             patch:after="processor[@type='Sitecore.Pipelines.HttpRequest.LayoutResolver, Sitecore.Kernel']">
    <param desc="Allowed sites">my-sitename-a, my-sitename-b, my-sitename-c</param>
  </processor>
</httpRequestBegin>

Note the param element that includes a list of site names that are allowed to execute this pipeline processor.
The way this works is that you can add any parameter and Sitecore will pass those values on to the constructor of the processor.

So if you define this processor:

<processor type="MyNamespace.MyProcessor, ParTech">
    <param>first value</param>
    <param>second value</param>
</processor>

Sitecore will initialize the processor like this:

new MyNamespace.MyProcessor("first value", "second value")

The desc attribute is ignored (as is any other attribute you put on the param element), but it's best practice to put a description of the parameter in there so that someone that's reading the configuration can make sense of it.

IsolatedProcessor class

In order to make my code reusable, I've created an abstract class that can be used on all pipeline processors.
The class offers a constructor which requires a comma-separated string with site names which will be read from the configuration before Sitecore initializes it.

Once you inherit your custom processor from the IsolatedProcessor class, you can use the IsAllowedRequest property to check if the processor is allowed to run in the current context (i.e. is allowed to run for the current site).

using System;
using System.Linq;
using Sitecore;

/// <summary>
/// Sitecore pipeline processor which can be configured to run only for specific sites.
/// </summary>
public abstract class IsolatedProcessor
{
    private readonly string[] allowedSites;

    /// <summary>
    /// Initializes a new instance of the <see cref="IsolatedProcessor" /> class.
    /// </summary>
    /// <param name="allowedSites">
    /// Comma-separated string with names of the sites for which this processor must run.
    /// </param>
    protected IsolatedProcessor(string allowedSites)
    {
        this.allowedSites = (allowedSites ?? string.Empty)
            .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
            .Select(x => x.ToLower().Trim())
            .ToArray();
    }

    /// <summary>
    /// Gets a value indicating whether this instance is allowed to run in the current context.
    /// </summary>
    protected bool IsAllowedRequest
    {
        get 
        {
            return this.allowedSites.Length == 0 
                || this.allowedSites.Contains(Context.GetSiteName().ToLower());
        }
    }
}

Here is an example of how I implemented the IsolatedProcessor for the ItemVersionValidator processor.

public class ItemVersionValidator : IsolatedProcessor
{
    public ItemVersionValidator(string allowedSites = null)
        : base(allowedSites)
    {
    }

    public void Process(HttpRequestArgs args)
    {
        // Only process allowed requests.
        if (!this.IsAllowedRequest)
        {
            return;
        }

        // Execute processor logic.
        if (Context.Item != null && Context.Item.Versions.Count == 0)
        {
            Context.Item = null;
        }
    }
}

As mentioned before, you can use the same IsolatedProcessor base class on every type of pipeline processor.
You can easily extend it with extra parameters by adding them to the constructor and configuration, and add logic that will deny specific sites and allow the rest.

Isolating event handlers

So does this work for event handlers as well?
No exactly, but it turns out you can do a similar thing with them:

<events>
  <event name="myevent">
    <handler type="ParTech.Events.DemoEvent, ParTech" method="MyMethod">
      <sites hint="list">
        <site>my-sitename-a</site>
        <site>my-sitename-b</site>
        <site>my-sitename-c</site>
      </sites>
    </handler>
  </event>
</events>

In this example, if your event handler class has a Sites property of a list type, such as ArrayList or List<string>, it will populate that property with the values from the configuration.
So the code for my DemoEvent class could be this:

public class DemoEvent
{
    private readonly List<string> sites = new List<string>();
    
    // Based on the configuration shown above,
    // this property will contain the values:
    // "my-sitename-a", "my-sitename-b", "my-sitename-c"
    public List<string> Sites
    {
        get { return this.sites; }
    }
    
    public void MyMethod(object sender, EventArgs e)
    {
        // Event handler logic...
    }
}

Now that you have a way of passing configuration values to your event handler, it shouldn't be too hard to implement a base class that helps you with isolating the handler per site.

Conclusion

It can be very useful to isolate pipeline processors and event handlers for specific sites.
Allowing that isolation to be configurable from the Sitecore configuration makes your solution easier to maintain.

Again, don't forget to read the follow up post about Configurable pipeline processors and event handlers!

Plaats een reactie