Umbraco developer productivity with uSiteBuilder
After having used Umbraco for 2 years, I keep looking for ways to make my life even easier. As you may know, initial deployment of an Umbraco site is super easy. But then, a few weeks later, you've enhanced your site, added fields and macros and suddenly.. you have to remember and repeat those steps on your live server..
This is not what you want, it's labor intensive, prone to mistakes and there's no way to do any kind of continuous integration. The kind people at Vega IT Sourcing must have felt the same way and developed a solution for this called uSiteBuilder.
The setup that I've chosen for this is a little bit different from the default that you get when out of the box. I've just downloaded and built the source of uSiteBuilder and from the "Vega.USiteBuilder\bin\Debug" folder I took the Vega.USiteBuilder.dll to use in my project.
My default Umbraco solution looks a bit like this:
More on how I set this up can be found in the Easily debug your custom Umbraco user controls in Visual Studio blog post. I still use that setup, except now in VS2010 and I only have 2 projects in there: the Umbraco site and my custom code organized in folders.
I reference the uSiteBuilder dll in the "SomeCompany.Extensions" project and then I'm ready to get started.
My post-build events look like this by the way:
XCOPY "$(ProjectDir)bin\SomeCompany.*" "$(ProjectDir)..\Umbraco\bin\" /y
XCOPY "$(ProjectDir)UserControls\*.ascx" "$(ProjectDir)..\Umbraco\UserControls\" /y
XCOPY "$(ProjectDir)Masterpages\*.master" "$(ProjectDir)..\Umbraco\masterpages\" /d /y
I really don't want to build my project every time I make a change to a masterpage file, I change my masterpages in the Umbraco site, not in the Extensions project. So for masterpages, I've added the extra /d parameter that will make sure only files that are newer in the Extensions project get copied to the website.
Master pages
Let's start with setting up a master page for the site, called Main, and a nested master page for the content of my TextPages.
Just right click in the Masterpages folder in the "SomeCompany.Extensions" project and create a new Masterpage called Main. The one thing we're going to change for now is setting the MasterPageFile to Umbraco's default MasterPage.
<%@ Master Language="C#" AutoEventWireup="true"
CodeBehind="Main.master.cs"
Inherits="SomeCompany.Extensions.MasterPages.Main"
MasterPageFile="~/umbraco/masterpages/default.master" %>
We'll get back to this Masterpage later.
Document Types
The most important feature of uSiteBuilder is that you can create your document types in code, instead of through the Umbraco interface. You just build a dll and drop it in your site's /bin folder. Once you do, the document type definitions that you've made get updated in Umbraco's database and, presto, no more manual deployments for document types!
As you might have read, I set up all of my sites using a SiteSettings node first and everything else goes under that. My goal is to get a document type structure that looks like this:
So let's get started with some code in DocumentTypes\SiteSettings.cs:
using Vega.USiteBuilder;
namespace SomeCompany.Extensions.DocumentTypes
{
[DocumentType(Name = "Site Settings", IconUrl = "house.png", Thumbnail = "developer.png", AllowedChildNodeTypes = new[] { typeof(TextPage) })]
public class SiteSettings : DocumentTypeBase
{
[DocumentTypeProperty(UmbracoPropertyType.ContentPicker, Name = "Homepage", Tab = "Settings", Description = "The item that you pick here will be the homepage of your site.")]
public string umbracoInternalRedirectId { get; set; }
[DocumentTypeProperty(UmbracoPropertyType.TextboxMultiple, Name = "Google Analytics Code", Tab = "Settings", Description = "Paste your Google Analytics code here to get statistics of your website")]
public string googleAnalyticsCode { get; set; }
}
}
Make sure to go through the uSiteBuilder tutorials if you're not sure what's actually going on here.
Great, that's that sorted, we can continue to the PageSettings document type:
using Vega.USiteBuilder;
namespace SomeCompany.Extensions.DocumentTypes
{
[DocumentType(Name = "Page Settings", IconUrl = "folder.gif", Thumbnail = "folder.png", AllowedChildNodeTypes = new[] { typeof(TextPage) })]
public class PageSettings : DocumentTypeBase
{
[DocumentTypeProperty(UmbracoPropertyType.Textstring, Name = "Page title", Tab = "Page settings")]
public string pageTitle { get; set; }
[DocumentTypeProperty(UmbracoPropertyType.Textstring, Name = "Meta title", Tab = "Page settings")]
public string metaTitle { get; set; }
[DocumentTypeProperty(UmbracoPropertyType.Textstring, Name = "Meta description", Tab = "Page settings")]
public string metaDescription { get; set; }
[DocumentTypeProperty(UmbracoPropertyType.TrueFalse, Name = "Hide in navigation?", Tab = "Navigation")]
public string umbracoNaviHide { get; set; }
}
}
The PageSettings document type is just a set of generic properties that I am going to need on all of my publishable content pages. I would generally also add checkboxes for "Hide in sitemap", "Show in main menu", "Show in footer menu", etcetera.
I've cheated a little bit here, as you can see, I am allowing documents of type "TextPage" under the SiteSettings, but we haven't actually defined the TextPage yet. We'll fix that right now:
using Vega.USiteBuilder;
namespace SomeCompany.Extensions.DocumentTypes
{
[DocumentType(Name = "Text page", IconUrl = "page.png", Thumbnail = "docWithImage.png", AllowedTemplates = new [] { "TextPage" }, DefaultTemplate = typeof (TextPage))]
public class TextPage : PageSettings
{
[DocumentTypeProperty(UmbracoPropertyType.RichtextEditor, Name = "Content", Tab = "Content", Description = "")]
public string bodyText { get; set; }
}
}
I am inheriting from the PageSettings class that I've just created so that TextPage will be nested under it.
Also, I have set the AllowedTemplates to TextPage, which doesn't exist yet. So it can now be created.
I've created a ContentPlaceHolder in Main.master:
<asp:ContentPlaceHolder Id="body" runat="server"></asp:ContentPlaceHolder>
Now I need to create the TextPage Masterpage by adding a new nested masterpage, based on Main.master:
We could just copy both masterpages (Main & TextPage) over to the site, but it will not do anything as we haven't told uSiteBuilder to pick it up and create the templates in Umbraco.
So, as promised, we're getting back to Main.master. Go into the codebehind and change it to inherit from SiteSettings, like so:
public partial class Main : Vega.USiteBuilder.TemplateBase<DocumentTypes.SiteSettings>
A similar inherit is necessary for TextPage, but it will be from the TextPage document type. This will make sure that the docType knows how to find the template that it is allowed to use:
public partial class TextPage : Vega.USiteBuilder.TemplateBase<DocumentTypes.TextPage>
What can we not do?
There has been a lot of good news in this article so far. It's easy to create document types and templates and I haven't covered this, but it's also very easy to create UserControl macros from uSiteBuilder.
But uSiteBuilder is still incomplete at the moment. There's no way to create XSLT macros and you cannot predefine the sorting of tabs on your document types (although you can just sort them manually in Umbraco's interface, that works just fine). Furthermore, there's no way to create media types either.
As this is an open source project, I have good hopes that someone will create the missing bits as they need them. For now, I've been able to work around them really well though.
That being said, it only took me about an hour or to get started with it and even if I would still need to do some things manually, I can still gain a lot in productivity for the supported features, which is fantastic!
Putting it all together
This is a completely reusable way of creating your site structure. In your next project you can just start out with these basic document types and templates and build them out as needed.
Another nice advantage of having your document types as classes is that it's so easy to open them up and find the exact alias of a property to use in our Razor scripts, no more going to "Settings" > expanding "Document types" > going to the "Generic properties" tab and finding the alias.
Finally, as an added bonus, using Razor is really what makes it able for me to work with uSiteBuilder without problems, as you can create Razor macro's without.. creating a macro.
That's right, it's as easy as referring to a file. In your template, just insert a macro like this:
<umbraco:Macro FileLocation="~/macroScripts/MainMenu.cshtml" runat="server" />
So, now when you deploy your site, all you need to do is move around the changed files. Don't forget the "SomeCompany.Extensions.dll", together with "Vega.USiteBuilder.dll" it will start creating and modifying your docTypes and templates.
Thanks to the great folks at Vega IT Sourcing for a truely awesome tool that makes my life much easier, I love it!
15 comments on this article
Simon Dingley | May 9 2011 09:15
Good article Sebastiaan, you beat me to it. I have a post coming up in the near future on the same subject but it's always interesting to see other peoples project structures. In the case of yours - it is quite different to mine and that's what I like about Umbraco there are many different ways of reaching the same goal!
ismail mayat | May 9 2011 09:35
Sebastiaan,
Awesome stuff the stuff you cant do is putting me off that the moment but reckon future releases will resolve those issues. Cant wait for a session at cg11 from you ;-}
Ismail
Lee | May 9 2011 09:50
Great stuff Seb! Just like Simon I love seeing how other people have their stucture.
I have looked at uSiteBuilder but think I'll wait until its a bit more mature before I start chucking loads of time into it.
Hope to see more blogs like this in the future :)
Niels Hartvig | May 9 2011 09:53
Code First is all the rage these days. In the Umbraco world as well, just wait and see :-)
Sebastiaan Janssen | May 9 2011 10:05
@Simon Would love to see other setups as well, bring it on.
@Ismail Don't be put off, it takes about an hour to learn and you gain in productivity immediately.
@Lee It's pretty easy to learn and use, try it on your next project.
@Niels I (quite literally) can't wait!
Janusz Stabik | May 9 2011 10:07
Great article. Been meaning to give this a try - the quick and easy way of finding alias's makes it all worth for me!
Simon Dingley | May 9 2011 10:08
To those who are putting off using uSitebuilder because because of what you can't currently do, I would urge you to give it a go. I have encountered no show stoppers and what you can't do in uSitebuilder you can do in the UI but for me that has so far only been the ordering of tabs.
For me the reasons for using uSitebuilder far outweigh any reasons not to at this point in time!
Sebastiaan Janssen | May 9 2011 10:11
Spot on Simon!
Niels Hartvig | May 9 2011 10:54
The main thing that needs to be improved in uSitebuilder is the license which currently is LGPL. It's a *ridiculously* complex license (especially compared to MIT/BSD).
Make sure to read and understand the LGPL license before putting sites based on uSitebuilder in production.
Or even better - tell the uSitebuilder people to change their license to MIT/BSD (I've tried!)
Sasa Popovic | May 9 2011 23:28
@Sebastiaan A very good article! You are right; we felt the same as you when we decided to build uSiteBuilder. We use it for more than a year now and our productivity has increased dramatically. Two things that I personally like the most are extremely easy collaboration in larger teams and how it is easy to make updates in a website after you didn’t work on it for a few months.
@Niels I remember you mentioned that you find LGPL very complicated but I really can’t think of any limitations of LGPL that would affect people who use uSiteBuilder; could it be that you were thinking about the GPL license? The GPL is much more restrictive and complicated in my opinion. You can check this nice and simple comparison of licenses (both LGPL and MIT are there): http://developer.kde.org/documentation/licensing/licenses_summary.html. There are a number of open source projects out there that we use in every day work that are licensed under LGPL; some of the most popular ones are TinyMCE, NHibernate, etc but there are much more that are not so popular.
@Everyone But still, if we overlooked real showstoppers in LGPL we will certainly think again and reconsider our decisions. We already accepted Niels’ remarks just after the launch of uSiteBuilder and switched from closed source to LGPL. Feel free to send us your feedback on the licensing model as you continue to use uSiteBuilder.
Niels Hartvig | May 10 2011 09:36
Contrary to completely non restrictive licenses such as BSD/MIT, LGPL *does* come with restrictions on how you distribute linked/used libraries (some of which is still unclear / unsorted). That's why we've chosen MIT for the Umbraco core. You could ask Darren Ferguson about his experiences with a persistent/regid owner of a LGPL licensed library that he used to use in one of his projects - that should emphasize worries on unclear licenses.
LGPL for tinymce isn't an issue as the source is always distributed (due to the nature of javascript) and NHibernate is forced to go LGPL due to it's origins from Hibernate.
I've never understood the idea of free software (as in freedom) that comes with a massive list of definition of free. I simply think that time has moved from those :-)
Indrakumar | May 10 2011 14:00
Iam using uSiteBuilder in one of my project I agree that uSiteBuilder simplify our project development, specially large project can be develop very fast and
make deployment very easy. One thing I like most about it is the .net way of development.
I hope future releases will incorporate lots of feature.
Damian | August 7 2012 14:34
Hi,
What are all the
etc
type codes in the code views?
Is it just html thats not getting rendered correctly?
Also - Are you still using uSitebuilder?
Damian | August 7 2012 14:36
ha... it stripped them out in the comments
< br id="mf77" >
Did that work?
Sebastiaan Janssen | August 7 2012 14:38
Hmm, they are just wrongly inserted in the rich text editor I suppose. :-)
Still using it, still pretty happy with it, but it has performance problems if you have more than.. about 20 document types.