Percipient Studios logo

Make an App_Code XSLT extension for Umbraco

12 November 2010
Filed under: umbraco, xslt - by Douglas Robar

You may have noticed that XSLTsearch 3.0 moved all the C# helper functions from in-line scripting within the XSLT file itself to /app_code/xsltsearch.cs. The reasons for doing this and how to create XSLT extensions without Visual Studio are the subject of this article.

What is the App_Code folder you ask? As Microsoft puts it, "you can store source code in the App_Code folder, and it will be automatically compiled at run time. The resulting assembly is accessible to any other code in the Web application. The App_Code folder therefore works much like the Bin folder, except that you can store source code in it instead of compiled code.

 

Extending XSLT's capabilities

Compiled XSLT extensions

In the past, when you wanted to add a little extra oomph to your XSLT macro you probably would have created an XSLT extension in Visual Studio, compiled it to a dll, copied it to the /bin folder of your site, and referenced it by updating the /config/XSLTextensions.config file.

Simple, no?

Well, to be honest, sometimes it does seem a bit over the top for just a few lines of .Net code. Especially if you aren't a .Net Jedi™.

What's wrong with <msxml:script> blocks?

The other option in such a case is to place your .Net code in an <msxml:script> block directly in your xslt file. I've found this to be a powerful and easy-to-implement solution. Indeed, all versions prior to XSLTsearch 3.0 used this technique as well.

There are down-sides to inline script blocks, though. For one thing, the macro will compile itself every single time the macro is run. That doesn't take long, but it adds up. Worse, you'll find a lot of tiny files from those compilations cluttering your system TEMP folder. This is especially evident if you haven't disabled debugging in the web.config file. These are small files but on a busy site they add up quickly and could potentially fill your system drive. And because the system TEMP folder is outside your website your macro won't run in medium trust.

Benjamin Howarth (@benjaminhowarth) discussed these and more in his illuminating presentation at the Umbraco 5th Birthday party in London, Medium Trust for Umbraco 4.x.

I still like the benefits of inline scripting:  all code is available for easy inspection, learning, and editing, and you never have to fire up Visual Studio ("oh, that project was created with VS 2005 and I only have VS 2099… hmmmm"). On the other hand, the downsides of not creating a proper XSLT extension are fairly significant.

Welcome to App_Code XSLT extensions in Umbraco

New to Umbraco 4.5, XSLT extensions in the /App_Code folder provides the best of both worlds! Code that is right in front of you and easy to edit, even for non-"VisualStudio junkies". And, you get strongly-defined (safer), cached-at-application-level (faster), and medium-trust-support (cheaper hosting). Wow!

And it is so easy to do! Let me show you how.

 

Reworking an old example

I'm going to re-work an older post entitled, Advanced XSLT with .NET Namespaces. You might want to read that article if the following code doesn't make sense to you.

In that older article I used an inline script block to determine the size of an uploaded file. This is something that can't be done from XSLT alone so I added the following C# script block. Let's remove the code from the script block and put it in an App_Code extension.

<msxml:script language="CSharp" implements-prefix="ps">
    <msxml:using namespace="System.IO" />
    <msxml:assembly name="System.Web" />
    <msxml:using namespace="System.Web" />
 
    <![CDATA[
    public String uploadFileSize(String filePath) {
 
        if ((filePath != null) && (filePath.Length != 0)) {
            String localFile = HttpContext.Current.Server.MapPath(filePath);
            if (File.Exists(localFile)) {
                FileInfo fileinfo = new FileInfo(localFile);
                return String.Format("{0:#,###,###.##}", (fileinfo.Length / 1024));
            }
        }
        return null;
    }
    ]]>
</msxml:script>

1. Create a file in the /app_code folder

All we have to do to convert this script block to a proper XSLT extension is create a file in the /app_code folder of my site. I'll call it PShelpers.cs. You can create these App_Code XSLT extensions with Notepad, Visual Studio (tip: create a 'Class Library' project), or anything in between.

Your baseline, starting file should look like this:

using System;
using System.Collections;

namespace ClassLibrary
{
    public class Class1
    {
    }
}

2. Name your class and namespace, add references

Now, change the namespace and class names for your project, add the umbraco api reference and any other namespaces you might need:

using System;
using System.Collections;
using System.IO;
using System.Web;
using umbraco;

namespace PS
{
    public class Helpers
    {

    }
}

3. Add [XsltExtension] and zero-parameter constructor

Add the [XsltExtension] line to the namespace and create a a zero-parameter constructor so that Umbraco will automatically pick this up as an XSLT extension:

using System;
using System.Collections;
using System.IO;
using System.Web;
using umbraco;

namespace PS
{
    [XsltExtension]

    public class Helpers
    {
        public Helpers() { }
    }
}

4. Paste the code from your script block

Now all you do is copy-n-paste the code from your script block.

Remember, all your functions must be public static.

Here's the final version of our re-worked example, this time as an App_Code XSLT extension:

using System;
using System.Collections;
using System.IO;
using System.Web;
using umbraco;

namespace ps
{
    [XsltExtension]

    public class Helpers
    {
        public Helpers() { }

        public static String uploadFileSize(String filePath)
        {

            if ((filePath != null) && (filePath.Length != 0))
            {
                String localFile = HttpContext.Current.Server.MapPath(filePath);
                if (File.Exists(localFile))
                {
                    FileInfo fileinfo = new FileInfo(localFile);
                    return String.Format("{0:#,###,###.##}", (fileinfo.Length / 1024));
                }
            }
            return null;
        }

    }
}

 

Using your XSLT extension

Now that you have a functioning XSLT extension you can remove the msxml:script from your xslt file and update the references to the new namespace and class. In our example, from 'ps' to 'PS.Helpers'. The macro will work as before, only in medium-trust and with better performance.

Additionally, when you create a new macro in Umbraco your App_Code XSLT extension will automatically be referenced. And when you click the 'Insert xsl:value-of' toolbar button in Umbraco's XSLT editor you can select your App_Code XSLT extension for point-n-click simplicity.

Insert Value in XSLT dialog box 

Select your extension and functions

 

"Gotcha" - only one language in App_Code

An important point to mention is that all the files in App_Code must use the same .Net language. You cannot mix C# for some files and VB.net for others, for instance. However, there is a solution if you must mix languages in the /app_code folder.

"Gotcha" again - App_Code bugs give YSOD

Never edit anything in the App_Code folder on a live site. If you make a mistake the site may display a Yellow Screen of Death (YSOD). In some cases even the Umbraco back end won't respond properly, or the site's application pool may shut down after repeated errors. You've been warned and I take no responsibility. Okay? Okay. But… if you are careful with your code (as of course you will be) then app_code is no more dangerous than a dll.

1 comment for “Make an App_Code XSLT extension for Umbraco”

  1. Gravatar of погружение шпунта
    погружение шпунта says:
    У вас кривая RSS — исправте
 
powered by <XSLTsearch>

Categories

Follow Us

RSS Feed
Follow us on Twitter
Follow us on Flickr