Archive

Archive for November, 2008

HAML Rendering for Sitecore

November 26, 2008 3 comments

I first heard about Haml (XHTML Abstraction Markup Language) early this year on Alexey’s blog. At first I thought “What’s the point?”. After all, HTML is easy to understand and is itself a markup language. Why do I need a markup language for a markup language? But when you start writing in this higher level language everything starts to zen.

I have started to become a fan of significant whitespace used to both indent code properly and define code blocks. I always indent my code correctly and it annoys me when I come across someone else’s code when they haven’t. One problem with code or markup which is not indented correctly is that when you’re reading the code, you generally read the indentation rather than the code block closing tags. For example, in the following example it is quite easy to miss the closing tag.

<div class="myclass"><div id="nav">
  <ul>
    <li><a href="somelink.aspx">Link</a></li>
  </ul>
</div>

Just because the second div on the top line wasn’t on a line of it’s own, it’s very easy to miss and screw up your markup. Yes, Visual Studio helps a great deal with making sure your tags are closed, but what if you’re not using Visual Studio? What if you’re using the Developer Centre in the Sitecore desktop?

So I’ve written a Haml rendering for Sitecore to allow you to write your renderings in Haml. You can download version 1.0 from my website http://users.tpg.com.au/adeneys/sitecoreHamlRendering.html.

I’m hoping to put this into Sitecore shared source along side my other Sitecore tweaks so everyone can easily access the module and code and also help to enhance the module. Version 1.0 is functional, but I eventually want to have the Haml rendering available in the Developer Centre as a rendering option along side XSLT renderings.

Categories: Sitecore

A generic error occurred in gdi+

November 19, 2008 1 comment

I had the above error the other day when using a new install of Sitecore. At first the error doesn’t seem to reveal much, and it quite … generic :) . This was happening when I was trying to create a new rendering through the developer centre in the Sitecore desktop. The full error was:

gdi error

And the error is logged in the log file as well.

Exception: System.Runtime.InteropServices.ExternalException
Message: A generic error occurred in GDI+.
Source: System.Drawing
at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder,
  EncoderParameters encoderParams)
at System.Drawing.Image.Save(String filename, ImageFormat format)
at Sitecore.Resources.FileIcon.GetIcon(String extension, Int32 width,
  Int32 height, Color background)
at Sitecore.Resources.FileIcon.GetIcon(String extension, ImageDimension dimension)
at Sitecore.Resources.FileIcon.GetFileIcon(String filename,
  ImageDimension dimension)
at Sitecore.Data.DataProviders.FileSystemDataProvider.GetItemFields
  (ItemDefinition itemDefinition, VersionUri version, CallContext context)...

For those that don’t know, GDI+ is basically the .net drawing subsystem. It is a hook into the Windows GDI subsystem. Normally when you start getting errors in GDI+ it indicates a low level problem, or some bad parameters or something.

And if we start to read the stack trace above we can see that an Image was being saved when the error occurred. But all I was doing was creating a new rendering. That’s not an image. And this error happens when the dialog tried to open before I have a chance to even select anything. I know from playing with the wizards in Sitecore’s Sheer UI that each wizard view can have an associated image which is displayed. That’s the only image I could think of in this instance.

The error occurred when trying to save the image. What could cause an error in that case? The first thing that came to mind was file permissions. If I don’t have permissions to write to a location, that might cause an error. And that’s exactly what was happening. The account under which ASP.NET was running didn’t have permissions to write to the “temp” folder under the root of the website. I adjusted the permissions so the account could write there, and voila, the error was gone.

Categories: Sitecore

ChangeTemplate with Revolver

November 13, 2008 Leave a comment

One of the goals of Revolver is to provide a platform for custom tool development and execution. Often we need to execute some code against an arbitrary set of items from the content tree. For example, yesterday I had to change the template of most of the items in the content tree of the site I was working on. And I wasn’t about to click through 200 items changing templates using the content editor. Enter Revolver!

Revolver allows you write your own Revolver commands and bind them into the Revolver shell. Your command must implement the Revolver.Core.ICommand interface. An easy way to do this is to inherit a class from Revolver.Core.Commands.BaseCommand which handles the initialisation stuff to store the Revolver context objects and provide access to them through properties.

So, for my above scenario, I know I could use the Sitecore.Data.Items.Item.ChangeTemplate method. So I will create a custom command to execute this method on the context item in Revolver.

First, create a new class library project in Visual Studio and add references to the Revolver.Core and Sitecore.Kernel assemblies. Now add the appropriate usings to your code file.

using Revolver.Core;
using Revolver.Core.Commands;
using Sitecore.Data.Items;

Next, create a new class which inherits from BaseCommand and implement the abstract methods.

namespace ChangeTemplate
{
  public class Command : BaseCommand
  {
    public override string Description()
    {
      throw new NotImplementedException();
    }

    public override HelpDetails Help()
    {
      throw new NotImplementedException();
    }

    public override CommandResult Run(string[] args)
    {
      throw new NotImplementedException();
    }
  }
}

We need to implement 3 methods. The first is Description which returns a string describing what the command does. The second is Help, which returns a HelpDetails object containing the help information for the command. These methods are called from the help command inside Revolver. Lastly, the Run command is what gets called when we execute our custom command in Revolver. The string array passed to this method are the parameters passed on the command line from the Revolver shell.

So let’s start implementing the help methods.

public override string Description()
{
  return "Change an item's template";
}

public override HelpDetails Help()
{
  HelpDetails details = new HelpDetails();
  details.Description = Description();
  details.Usage = "<cmd> templatePath";
  details.AddParameter("templatePath", "The template to change to");
  details.AddExample("<cmd> (sample/sample item)");
  return details;
}

The Description method is called when the help command is executed without any parameters and the output is displayed in a list of the available commands next to the currently bound command moniker. The Help method is called when the help command is executed and passed the current moniker for the command to get more detailed help information for the command.

Note in the HelpDetails object for usage and example I don’t use any particular command moniker, but instead use the placeholder “<cmd>”. This is because the custom command may be bound to any moniker at all. Fill in as many of the HelpDetails properties as possible to provide the user with enough information to be able to use your command.

And now, onto the Run method. This method returns a Revolver.Core.CommandResult object which indicates the success or failure of the command as well as any messages to pass back to the user.

public override CommandResult Run(string[] args)
{
  if (args.Length < 1)
    return new CommandResult(CommandStatus.Failure,
      "Failed to find required parameter 'templatePath'");

  TemplateItem template = Context.CurrentDatabase.Templates[args[0]];
  if (template == null)
    return new CommandResult(CommandStatus.Failure,
      "Failed to find template " + args[0]);

  Context.CurrentItem.ChangeTemplate(template);
  return new CommandResult(CommandStatus.Success,
    "Changed template to " + args[0]);
}

The Context property is provided by the CommandBase class which took care of storing the Revolver context and format context objects.

Now that my command is implemented I can bind the command into a Revolver shell and execute it against the items required. Firstly, build the code and place the output assembly in the bin folder of the Sitecore site you’re going to use it in. Next, log into Sitecore and open a Revolver shell. We use the bind command to bind the custom command into the shell. Let’s bind the change template command to the moniker “ct”.

bind ChangeTemplate.Command,ChangeTemplate ct

The first parameter provided to bind is the fully qualified type name. The second is the moniker to bind the command to.

Now I can execute the change template command by executing ct and providing the template I wish to change the current item to.

ct (sample/sample item)

But I’m only in a slightly better position than I was at the start of the article. I’m not going to navigate round 200 items in my content tree to execute a command. And this is where the real power of Revolver comes in. I can combine by command with the find or query commands to have it execute against a set of items. In my scenario, I need to change all items which currently have a template of ‘sample item’ and change it to ‘real item’. So I’ll be using the attribute filter on the find command.

find -a templateid {76036F5E-CBCE-46D1-AF0A-4143F9B557AA} (ct (real item))

or

find -a template (/sitecore/templates/Sample/Sample Item) (ct (real item))

And what’s more is I managed to throw the above custom command together and execute it against the content tree within 10 minutes. I just saved myself hours and countless frustration.

Categories: Revolver

Automated Testing and Sitecore – Part 8

November 8, 2008 6 comments

Well. When I started writing this multi-part series on automated testing and Sitecore I never intended for it to flow over into 8 parts. But I think what I’ve covered in this series are the fundamental pieces any developer requires to be able to affectively automate their tests for Sitecore code.

So, now that we’re at the end of the series, I’ll leave you with some tips.

  • Don’t get hung up on “unit” testing. As you’ve seen, it’s very difficult to completely isolate any code we write against the Sitecore API, as that API is a dependency. Also at times, the entire Http Request becomes a dependency when we’re testing components which are context sensitive. Don’t worry too much about ensuring you’re testing is “unit”. Unit testing makes it easier to pinpoint which piece of code is misbehaving, but all we really need is an atomic, repeatable test harness for our code to ensure it behaves as expected. Once you let go of pure units, you’ll be able to write your tests a lot easier.
  • Plan for testing. I always start writing new pieces of code by thinking about how I could test that code. (Actually, I start by writing the tests so I’m TDD.) Is it presentation? Is it static in behavior? Do I need the custom test runner to provide a Sitecore context to the running tests? How will I make the test repeatable? What dependencies on the environment are there, such as, do I need to create any items to test the component?
  • Design for testing. Take note of how you write your code and how you design the architecture of your solution to make sure components are easily testable. For example, complex functionality should never be in the code behind of a sublayout or layout. It should always be in a different class. This makes the functionality available to other parts of the solution as well as making the testing of the logic of that function much easier as the logic is not mingled with presentation code.
  • Ensure your tests are repeatable. You want to be able to retest and retest and get consistent results. Part of this will most likely be setting up your content tree before the test so you know what results to expect. Being able to pragmatically setup the environment is paramount to making your tests repeatable. You don’t want to have to rely on a person creating certain items or setting up the environment manually before a test. Ensure there are as few steps as possible in the testing strategy. The closer you can get to “single click” testing, the less likely you are to have developers not running the tests to make sure they didn’t break anything.
  • Ensure your tests are atomic. You need to cleanup any test items created for the test at the conclusion of the test (or test fixture). You don’t want tests to impact on each other as these ends up leading to very messy maintenance. You need to ensure your tests can grow as your solution does and the biggest impact on this is the atomicity of your tests.

I hope the techniques I’ve shown in this series will help you on your way to better testing. But these techniques are still evolving. As I’m challenged by a new dev about the complexity of testing against Sitecore, or as I find better ways to test, I incorporate those into my testing techniques. I’ll keep you posted on what I find in the future. And of course if you think I’m completely off the mark about any of this, let me know. Only through challenging the technique do we truly assess it’s effectiveness and suitability.

Categories: .net, Sitecore
Follow

Get every new post delivered to your Inbox.