Sitecore 6 Validators

One of the cool features in Sitecore 6 is the ability to include validators on your fields. Any field can contain any number of validators, validating anything from the validity of the
HTML to the number of characters in a string.
And as always, Sitecore have made the validators completely open for developers to create their own validators.

So – lets make one. This small example will check to see if a text contains bad language (the actual bad language checker is not implemented – I’ll mark it in the code).

First I’ll create a new class that derives from Sitecore.Data.Validators.StandardValidator. Note that the whole class is Serializable. Sitecore uses this when the user cliks on the “Validate” button (the button with the icon shaped as a bug).

using System;
using System.Text;

using Sitecore.Data.Validators;

namespace Pentia

{
  [Serializable]
  public class LanguageValidator : StandardValidator
  {
    /// <summary>
    /// Initializes a new instance of the <see cref="LanguageValidator"/> class.
    /// </summary>
    public LanguageValidator(SerializationInfo info, StreamingContext context) : base(info, context)
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="LanguageValidator"/> class.
    /// </summary>
    public LanguageValidator()
    {
    }

    /// <summary>
    /// Gets the name of the validator.
    /// </summary>
    /// <value>The name.</value>
    public override string Name
    {
      get { return "LanguageValidator"; }
    }

    /// <summary>
    /// When overridden in a derived class, this method contains the code to
    /// determine whether the value in the input control is valid.
    /// </summary>
    /// <returns>The result of the evaluation.</returns>
    protected override ValidatorResult Evaluate()
    {
      // Get the value to validate
      string controlValidationValue = base.ControlValidationValue;
      // !!! Write your own bad language validator here !!!
      if (ContainsBadLanguage(controlValidationValue)
      {
        base.Text = "The text contains bad language";
        retrn ValidatorResult.CriticalError;
      }
      return ValidatorResult.Valid;
    }

    /// <summary>
    /// Gets the max validator result.
    /// </summary>
    /// <returns>The max validator result.</returns>
    /// <remarks>
    /// This is used when saving and the validator uses a thread. If the Max Validator Result
    /// is Error or below, the validator does not have to be evaluated before saving.
    /// If the Max Validator Result is CriticalError or FatalError, the validator must have
    /// been evaluated before saving.
    /// </remarks>
    protected override ValidatorResult GetMaxValidatorResult()
    {
      return base.GetFailedResult(ValidatorResult.CriticalError); 
    }
  }
}

That’s it. The “Name” property tells Sitecore what the name of the validator is. The Evaluate() function will evaluate the contents of the field. The GetMaxValidatorResult() tells Sitecore what the maximum error level is. You have 6 levels of validation to play with: Valid (do nothing), Suggestion (yellow color), Warning (orange color), Error (red color), CriticalError (also red) and FatalError. A CriticalError or FatalError will disable saving of the item.

The return text is set using the base.Text attribute, but I could also have used the base.Errors array. In the above example, it could be a nice feature to return the word that causes the validator to fail. I’ll rewrite my business logic:

string[] badWords = GetBadWords(controlValidationValue);
if (badWords.Count > 0)
{
  foreach (string word in badWords)
  {
    base.Errors.Add(word + " is a bad word and must be removed before saving");
  }
  return ValidatorResult.CriticalError;

}
return ValidatorResult.Valid;

It is very easy to install the validator. No web.config changes are needed. Just copy the validator DLL to the /bin/ directory of the web site and create a new validator under /system/settings/Validation Rules/Field Rules. You may also add your validator directly on a field type. This is done under /system/settings/Validation Rules/Field types.

The .ashx extension – Writing your own HttpHandler

Have you noticed how Sitecore serves images using an .ashx extension? A .ashx file is a HttpHandler. A HttpHandler is kind of a lightweight aspx page, as the HttpHandler only deals with the HttpContext - for example there is no page information. This makes it a great tool for implementing providers for images, xml, rss feeds or other stuff that can be generated using parameters only.

The .ashx file implements the System.Web.IHttpHandler (or the System.Web.IHttpAcynchandler for async calls – I’ll only show the first one), which contains only 1 property (IsReusable) and one function (ProcessRequest()). The ProcessRequest() function have one parameter only, the HttpContext to read and write data to.

My Visual Studio have no default creation of .ashx extensions, so I’ll have to make one manually. I create a new file with the .ashx extension and adds the following line:

<% @ WebHandler language="C#" class="MyNamespace.MyClass" codebehind="mycodebehind.cs" %>

Then I have to create a mycodebehind.cs file and add a class called MyNamespace.MyClass. This class should implement the IHttpHandler interface:

using System.Web;

namespace MyNamespace
{
  public class MyClass : IHttpHandler
  {
    public bool IsReusable
    {
      get { return true; }
    }

    public void ProcessRequest(HttpContext context)
    {
      // Here goes all of my code
    }
  }
}

Now my ProcessRequest can serve anything I like. I can reteieve paramaters from the Request and write to the Response:

public void ProcessRequest(HttpContext context)
{
  string parameter = context.Request.Params["myparameter"];
  context.Response.Write(parameter);
}

Or I can output a file (like Sitecore does):

public void ProcessRequest(HttpContext context)
{
  System.IO.MemoryStream ms = new System.IO.MemoryStream();
  Image image = SomeFunctionGeneratingAnImageForme();
  image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
  context.Response.ContentType = "image/jpeg";
  context.Response.OutputStream.Write(ms.GetBuffer(), 0, Convert.ToInt32(ms.Length));
}

I’ve noticed how Sitecore registers theit HttpHandlers in the web.config. You really don’t have to do that (even if Microsoft says so). You can call them directly. But if you wish to do so, you should read this article on how to register a HttpHandler.

Breadcrumb in Sitecore

In my quest for providing simpler topics about Sitecore development, I have decided to give you one of my simplest XSLT’s: the breadcrumb. This breadcrumb is probably used in every project I have ever implemented.
To create a breadcrumb you must read the current item, and all of it’s parents untill a you reach the front page and list them in the order from the front page and downwards to your own page. To do this, you must use the ancestor-or-self axis. This axis returns all descendants of your page and the page itself.
Here is the complete code. This is all you need:

<xsl:variable name="navigationItems" select="$sc_currentitem/ancestor-or-self::item[sc:IsItemOfType('mypages',.) and sc:fld('ShowInMenu',.)='1']"/>
<ul>
  <xsl:for-each select="$navigationItems">
    
	<li>
      <xsl:if test="position()>1">
        >
      </xsl:if>
      <sc:link text="{sc:clip(sc:fld('MenuTitle',.),20,1)}" />
    </li>
  </xsl:for-each></ul>

Here is how it works: First I use the ancestor-or-self axis to get all pages of a certain type (using sc:IsItemOfType(), see my blog on using this function) and with a certain property (using sc:fld(), see this blog on using sc:fld or sc:field).
The axis have done all the work for me. Now I can loop over each item and draw them in an unordered list. To seperate each of the items I draw a “>” but only if I am not drawing the first item (using position() > 1).
Notice how I draw the breadcrumb link. I use the sc:link() and clips the menu title (using sc:clip()) if the title is too long. 
You should replace “mypages“, “ShowInMenu” and “MenuTitle” with the appropriate values you use in your project.

Image resizing

The .NET GDI+ is not very fast, but it is actually very powerfull. A thing I have used the api for is to create thumbnail images. The GDI is capable of drawing images using both bilinear and bicubic interpolation. This means that your resized image will not have the sharp edges that occurs when resizing without any filters. 

This very small function will resize an image to the specified size:

using System.Drawing;
using System.Drawing.Drawing2D;

private Image CreateThumbnailImage(Image original, Size size)
{
  // Create new bitmap
  Bitmap b = new Bitmap(size.Width, size.Height);
  // Create a drawing surface 
  Graphics g = Graphics.FromImage(b);
  // Set the interpolationmode
  g.InterpolationMode = InterpolationMode.HighQualityBicubic;
  // Draw the original image to the new image
  g.DrawImage(original, 0, 0, size.Width , size.Height);
  // return the new image
  return b;
}

Notice that I set the InterpolationMode on the drawing surface. This tells the GDI+ how to draw an image. The HighQualityBicubic interpolationmode is probably the best setting, but also the slowest. You can also use HighQualityBilinear, Bicubic, Linear, or any of the other 9 modes.

Drawing images using an InterpolationMode is very slow, so try not using it in real time.