When working with Macros in Umbraco there’s always the decision of what type to go with, are you going with XSLT, a .NET user control, a .NET class or maybe a DLR script?
Here’s a few guidelines which we use at TheFARM to do macros.
Please note – although Shannon and myself are both on the Umbraco core team this is the opinion of us and does not necessarily reflect that of the Umbraco core team.
Choosing the right type
Umbraco supports several different ways which you can create a macro:
- XSLT
- .NET User Control
- .NET Custom Control
- DLR languages such as IronPython or IronRuby
Choosing the right tool for the job comes down to what you're trying to do with your macro. Generally speaking you'll be writing a macro that is either a XSLT or a .NET User Control. We currently don't use the DLR languages so using IronPython or IronRuby as the macro type isn't done (but if you can put forth a good case as to why we should we're happy to hear it!) and it's not often that you're going to require a macro which loads up a .NET control which is just a class (such as a CompositeControl or WebControl).
In fact in all the years I’ve been working with Umbraco I’ve never used a .NET Custom Control. In fact I’ve hardly ever had a need to create custom .NET server controls in all the time which I have work with ASP.NET.
When to use XSLT
XSLT is a powerful but miss-understood language and using it in Umbraco can be a really good idea or a really bad idea. XSLT is great for interacting with the Umbraco content cache, as the cache stores all the data as XML, which obviously XML is great at working with. When working purely with the XML cache it can be really fast.
But XSLT can become slow if you start introducing .NET into the mix. This can be in the form of XSLT Extensions, or embedded C# code in your XSLT file.
Here's a few rules as to when XSLT is the probably right way to go:
- Are you building a navigation system
- Navigation systems such as breadcrumbs, top or page-based navigations should always be done in XSLT
- Are you repeating content under the current node or something contextual from the current node
- If you're building something like a news article listing outputting with XSLT is often faster as the data is contextual
- Is the number of lines going to be small
- XSLT can be hard to read (well, XPath really) and once you start getting long XSLT files with multiple templates it can be very hard to follow where you're going in the file
Here's a few rules as to when XSLT is probably not the right way to go:
- Are you likely to debug
- Yes you can debug XSLT. No it's not as nice an experience as debugging .NET
- Do you have to write an XSLT extension
- If you have to write an XSLT extension that means that you need some .NET which has functionality too complex to express in XSLT. Try not to mix technologies
- Do you need to get nodes with a XPath selector like //node
- If you're using //node then you're looking at the XML file as a whole, so chances are you don't really know where your data is. This means you're having to process the whole XML file to find what you want, resulting in potentially slow code and scalability problems
Essentially what it comes down to is that XSLT is great if you're working with transforming the data for just the data to display on the UI, remember XSLT stands for Extensible Stylesheet Language Template Transformations ;).
When to use .NET
.NET is what we're most familiar with, so coding .NET seems the right thing to do, but despite popular belief .NET isn't the be all and end all when it comes to programming. .NET has a lot of advantages over the other macro types, but it can also introduce its own problems particularly around performance.
Here's a few rules as to when .NET User Controls are probably the right way to go:
- You're working with FADS
- You're interacting with an external data source
- UI should never directly access the data source
- You have business rules around the data
- Business rules don't have to be just external data reliant, they can be around the content too. Business rules can be generally expressed easier in .NET
- You plan to unit test
- This is kind of the same as the business rules point, but if you're writing business rules you should be unit testing them and unit testing XSLT is very hard
Here's a few rules as to when .NET User Controls are probably not the right way to go:
- You need fine-grade control over the markup generated
- Some .NET server controls have their own markup rules around them and outputting simple things can often be tricky (like menus or lists of data)
Macros vs Registered User Controls
When creating a .NET User Control you need to make a decision about whether you want to have it as a macro or whether you just register is as per normal in the Master Page. The general rule is that you shouldn't make something into a macro unless you need to pass data into it from the current Umbraco page, or you need to have the content editors place it anywhere they want.
Often a macro needs to have data passed into it from Umbraco, this could be a property which is set on the current page. This is an idea opportunity to use a Macro rather than just registering the user control as when Umbraco is processing the template and finding the macros it will assign any of these properties. This can save you from writing code to retrieve the value yourself.
The other reason is that you may want content editors to control where a macro is placed within a site. This can be handy for things such as Contact forms or news listings. By giving editors this freedom they can better control what pages do what in their site. But with great power comes great responsibility. If you're allowing macros to be inserts from the WYSIWYG editor (and this is applicable for XSLT macros as well as .NET) things can break so be sure to handle unexpected usage. A good rule of thumb is that a macro should only be allowable in the WYSIWYG editor if you know it can't break anything (design, functionality, etc).
Using a plain control registration though does have its own advantages. If you register the control yourself it will be faster as there is no dynamic creation of the user control instance from the Umbraco request, this is all handled via the ASP.NET runtime. It can also give you greater flexibility if you want to use features such as Dependency Injection, as you're running in the ASP.NET life cycle entirely, not being injected into the page from an outside source.
Our preference is to have controls registered in templates for .NET components.
Conclusion
Hopefully this simple set of guidelines will give you a bit of an insight into how we at TheFARM go about our Umbraco development.