Umbraco 4.5 & Visual Studio 2010 & .Less & jQuery vsdoc & SquishIt & masterpages
Using Umbraco with VS2010
… and masterpages, jQuery vsdoc, dotless, SquishItWelcome all to this magnificent blogpost about using Umbraco 4.5 with Visual Studio 2010 and everything you’ll need to know about some other tools!
First things first; we, at InfoCaster, use Visual Studio 2010 and .NET to develop our Umbraco web applications. We try not to use XSLT, just because .NET is much better
and everyone at InfoCaster knows .NET, unlike XSLT. I always like to say that .NET with LINQ can do like everything, but XSLT can’t or does things inefficient. It’s not even possible to assign a value to a variable for a second time. How variable is that ‘variable’ then? But that’s another discussion!
So a few months ago I started developing our own ‘Umbraco Website Starter project’. It’s like a clean Umbraco installation wrapped in a Visual Studio solution, with some extra’s, like some handy extension methods, pre-installed packages and default properties for the homepage (title prefix/suffix, Google analytics code, meta data etc.).
Now I migrated it to Umbraco 4.5 and removed all packages and installed the necessary packages again. I’d like to tell you all what I did and how.
Blueprint CSS
We’re using Blueprint CSS from now on to have a good start on creating our templates and stylesheets, this is combined with SquishIt.
.Less
We’re using .Less for our custom stylesheet. You can read everything about how to set this up in VS(2010), so I’m not going to explain that: http://www.dotlesscss.com/
I’m using SquishIt to generate the CSS files out of the .css.less files. These .css.less files can be opened with VS2010 with css highlighting / autocompletion by using this plug-in: http://visualstudiogallery.msdn.microsoft.com/en-us/dd5635b0-3c70-484f-abcb-cbdcabaa9923
<%= Bundle.Css()
.Add("~/css/blueprint/screen.css")
.Add("~/css/style.css.less")
.WithMedia("screen, projection")
.Render("~/css/output/screen_#.css")
%>
SquishIt and jQuery vsdoc
SquishIt download page: http://www.codethinked.com/post/2010/05/26/SquishIt-The-Friendly-ASPNET-JavaScript-and-CSS-Squisher.aspx
VS2010 has better intellisense features when it comes to JavaScript. So why not use jQuery with vsdoc and let SquishIt minimize and combine it for production environments?
Great idea! BUT this is how SquishIt requires it’s mark-up:
<%= Bundle.JavaScript()
.Add("~/js/jquery-1.4.2.js")
.Add("~/js/jquery-ui-1.8.1.js")
.Render("~/js/combined_#.js")
%>
Hmm… That’s not going to work with intellisense/vsdoc, because Visual Studio looks for real <script> tags…
So what I did is this:
<asp:Literal runat="server" ID="ltlScripts">
<script type="text/javascript" src="~/scripts/jquery-1.4.2.js"></script>
</asp:Literal>
Then you can just add any JavaScript reference you’d like
To enable vsdoc intellisense, you must also have the vsdoc file in the same folder as the realy jQuery file
The literal is being parsed in code-behind by using regex and it gets rewritten:
Regex scriptTagRegex = new Regex(@"<script(.*)type=""text/javascript""(.*)src=""(.*)"".*></script>");
IJavaScriptBundle jsBundle = Bundle.JavaScript();
IJavaScriptBundleBuilder jsBundleBuilder = null;
foreach (Match match in scriptTagRegex.Matches(ltlScripts.Text))
{
if (jsBundleBuilder == null)
jsBundleBuilder = jsBundle.Add(match.Groups[3].Value);
else
jsBundleBuilder.Add(match.Groups[3].Value);
}
ltlScripts.Text = jsBundleBuilder.Render("~/scripts/output/js_#.js");
Simple as that
(using SquishIt.Framework.JavaScript)
Default meta properties
(title prefix/suffix, meta tags, meta description, meta title, favicon, Google analytics)
This is the markup I have as <head>:
<head runat="server">
<title>Title will be filled from codebehind</title>
<!-- meta data -->
<meta name="author" content="InfoCaster B.V." />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="keywords" content="<%= CurrentNode.GetPropertyValueRecursive("pageKeywords") %>" />
<meta name="description" content="<%= CurrentNode.GetPropertyValueRecursive("pageDescription") %>" />
<asp:Literal runat="server" ID="ltlFavicon">
<!-- favicon -->
<link rel="shortcut icon" href="#HandledInCodeBehind" type="image/x-icon" />
</asp:Literal>
<!-- css -->
<%= Bundle.Css()
.Add("~/css/blueprint/screen.css")
.Add("~/css/style.css.less")
.WithMedia("screen, projection")
.Render("~/css/output/screen_#.css")
%>
<%= Bundle.Css()
.Add("~/css/blueprint/print.css")
.WithMedia("print")
.Render("~/css/output/print_#.css")
%>
<!--[if lt IE 8]>
<%= Bundle.Css()
.Add("~/css/blueprint/ie.css")
.WithMedia("screen, projection")
.Render("~/css/output/ie_#.css")
%>
<![endif]-->
<asp:ContentPlaceHolder runat="server" ID="cphHead" />
<!-- js @ bottom -->
<asp:Literal runat="server" ID="ltlGoogleAnalytics">
<!-- Google Analytics -->
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', '{0}']);
_gaq.push(['_trackPageview']);
(function () {{
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
}})();
</script>
</asp:Literal>
</head>
The title, favicon and Google analytics gets set from code-behind.
The meta tags/description are filled by using a recursive extension method I wrote.
I also added a content placeholder in the head and also at the end of the XHTML document, right before the </body>, so it’s possible to load custom CSS (head) and JS (bottom) per sub masterpage.
This is the code-behind which belongs to this mark-up:
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
#region Page stuff (google analytics, favicon, title)
// Google analytics
if (!string.IsNullOrEmpty(CurrentNode.GetPropertyValueRecursive("analyticsCode")))
ltlGoogleAnalytics.Text = string.Format(
ltlGoogleAnalytics.Text,
CurrentNode.GetPropertyValueRecursive("analyticsCode")
);
else
ltlGoogleAnalytics.Visible = false;
// Favicon
int faviconId;
if (!string.IsNullOrEmpty(CurrentNode.GetPropertyValueRecursive("favicon")) && int.TryParse(CurrentNode.GetPropertyValueRecursive("favicon"), out faviconId))
ltlFavicon.Text = string.Format(
"{0}{1}{2}",
ltlFavicon.Text.Substring(0, ltlFavicon.Text.IndexOf("href=\"") + ("href=\"").Length),
new Media(faviconId).getProperty("umbracoFile").Value,
ltlFavicon.Text.Substring(ltlFavicon.Text.IndexOf("href=\"\"") + ("href=\"").Length)
);
else
ltlFavicon.Visible = false;
// Title
Page.Title = string.Format(
"{0}{1}{2}",
CurrentNode.GetPropertyValueRecursive("titlePrefix"),
CurrentNode.GetPropertyValueOrDefault("pageTitle", CurrentNode.Name),
CurrentNode.GetPropertyValueRecursive("titleSuffix")
);
#endregion
}
Easy right?
Extension methods
I wrote some extension methods to ease some default tasks.
These extension methods are duplicated, for use in multilingual sites.
You can download the .cs file right here, it contains enough comments/documentation. Look at the end of this post
Masterpage intellisense VS2010 bug
There is a bug in VS2010 when using Umbraco’s masterpage as root master (umbraco.presentation.masterpages._default). The intellisense doesn’t work anymore. I’ve created a bug report on Microsoft Connect about this: https://connect.microsoft.com/VisualStudio/feedback/details/567771/no-asp-tag-intellisense-in-some-cases-when-using-masterpages
I’ve got a ‘dirty’ work-around. I don’t know if this work-around works with the ‘Canvas-editing’ feature in Umbraco (we and our customers don’t use it).
Just let every main masterpage (with <html> tags) inherit: umbraco.presentation.masterpages._default
#Protip: Creating new templates
When using Visual Studio, it’s nice to have code-behind files for your templates (at least, that’s how we do stuff). If you create a template in Umbraco, it creates a masterpage without code-behind…
Then you would have to add a code-behind manually, link it with the mark-up and create designer file. That sucks right?
Just do this:
- Create a nested masterpage in VS and use your ‘master’-masterpage as masterpage in the masterpages folder. Lol, there’s a lot of ‘masterpage’ in that sentence hehe.
- VS creates a masterpage for you with code-behind, sweet!
- VS opens the mark-up of this newly created masterpage, keep it opened!
- Then go to your Umbraco back-end and create a template like you would normally do. Give it the same name as you defined in step 1.
This should create an Umbraco template by using the already created masterpage as file. - Now return to Visual Studio. It should notify you that the file has changed and gives you the option to reload the file. Reload and then use CTRL+Z to undo the changes made by Umbraco (else the code-behind won’t be linked to the mark-up) and save it.
- You’re done!
Downloads
‘Master’-Masterpage with code-behind: StefanKip.InfoCaster.Umbraco.masterpage
Extension methods: UmbracoExtensions.cs (remove ending .txt)
This is great. Thanks for sharing your methods. It should come in handy for a lot of Umbraco devs.
Cheers!
Nice article.
I’ve been meaning to play with .LESS for ages. Will definatley be giving that a go.
RE SquishIt, What are the benefits of using that over the built in ClientDependancy?
Also, I’m no SEO expert, but speaking with an SEO friend of mine, he’s always told me it’s better to have no meta description/keywords than duplicates. So I can’t say I’m sold on the recursive thing. FYI though, you could also do the same using umbraco:item which then wouldn’t need your custom recursive method.
Nice post though, and there are definatley a few things I’ll be having a play with.
Thanks for sharing.
Matt
Thanks Nik & Matt
@Matt
I haven’t tried ClientDependency. I just think it’s too much, while SquishIt is nice and simple.
There were situations I experencied that recursion in Umbraco (like the macro parameter syntax and umbraco:Item) didn’t work correctly.That’s why I chose to create my own Recursion method.
As far as the SEO thingie: you’re trying to say that it’s better to have no description/keywords than the same description/keywords as it’s parent page?
Cool, simpler is always better =)
Hmmm, thats strange about the recursion. Have you raised an issue? Would be great if it could be fixed in the core, rather than people needing to create their own fix.
RE SEO, that is what I’ve been told yes. I would probably recommend that it might be better instead, to try and generate a description from the content itself, rather than reusing meta data.
Matt
Cool, I was expecting you to post this so fast it extremely helpful, must have a lot of time on your hands
Are you planning on realising your Umbraco Website Starter project, for the not so DEV’y umbraco users like myself?
@Ivor
LOL! So fast?! Haha!
I was planning to write this blogpost about 2 weeks ago
So I do not have a lot of time on my hands
I maybe will release this Website Starter Project… Have to discuss it at work. I’ll keep in touch about it. Do you by chance have twitter?
@kipusoep Yup i do have twitter, I’m following you already. my handle is @ivorthedesigner
Okay thanks
NIce article! I second Matt’s comment about duplicate Meta tags, from an SEO point of view its a bad thing to have duplicate tags on the site (I’m contracting at a big SEO agency at the moment, and have had this drilled into me)!
Thanks for your comment Tim
Will keep this in mind and maybe I’ll be able to create a nice package
Hi, great writeup. Was wondering how you “wrapped up” the Umbraco installation in VS? Do you keep a separate web-application project for your code and a website for Umbraco and do some post-build copying or do you roll everything together in to one website or web application?
Thanks!
@brent
It’s everything together
[...] .LESS and the Client Dependency Framework in Umbraco August 12, 2010 // 0 Inspired by a resent blog post by Stefan Kip and a conversation with Geert Pasteels on twitter, I thought it was about time I had a play with [...]
@kipusoep
if its everything together, don’t you have .cs files in the umbraco installation then? how do you deal with that?
Nope, I just downloaded the compiled version of umbraco
And I encapsulate the compiled version with this Visual Studio solution
yes but I mean, when u add new usercontrols and masterpages this way, the usercontrols and masterpages have .cs codebehind files, right? How do you deploy afterwards?
Yes, it works just like a ‘normal’ ASP.NET project. We always deploy using the built-in Visual Studio Deploy option. Code-behind files will not be deployed, instead the binary file (assembly) of the project will be deployed.
Ok sounds very nice. I’ll give this method a try for future projects.
I got 2 more newbish questions if you dont mind:
- You communicate with the DB in the masterpages. I hope this only happens upon publishing (to generate static pages without DB calls in the frontend)? I’m not that familiar with the caching/publishing mechanism and find it a bit odd that you use DB calls where xslt (that works on the cache xml) is normally used.
- When and where do you use the SaveAndPublish extension method in your extension methods file?
Thanks a lot for the replies
Thomas
These are indeed very basic Umbraco questions. If you have any questions in the future, please use http://our.umbraco.org, there are lot’s of helpful people over there
This blog isn’t really a forum you know 
Like:
Anyway:
1. There is no DB communication. The XSLT uses the umbraco XML cache file. .NET uses this file too when you’re using the umbraco NodeFactory or Linq2Umbraco.
2. When I want to Save and Publish a new or altered Document
Document d = new Document(docId);
d.GetProperty(“someProperty”).value = “some value”;
d.SaveAndPublish();
You must declare “using InfoCaster.Umbraco.Library;” when you want to use the extension methods.
Ok thanks a lot, I thought you meant linq2sql in your original post.
I was unaware there was something like linq2umbraco.
Thanks for the help!
“It’s not even possible to assign a value to a variable for a second time.”
That’s because it’s a functional programming language; it’s actually by design (rather than a missing feature). Variable, here, means something like this:
“Varying, in the context of mathematical variables, does not mean change in the course of time, but rather dependence on the context in which the variable is used.”
It’ll make more sense to mathematicians than to programmers, but at least there’s a reasonable explanation. Other functional programming languages work the same way, tho some may have implemented a work-around (and possibly violate the functional programming paradigm in doing so).
(See also: http://www.wisegeek.com/what-is-functional-programming.htm)
Rob, stop spamming about XSLT
It’s just bad