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.

"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.