<?xml version="1.0" encoding="UTF-8" ?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Cultiv</title>
        <link>https://cultiv.nl</link>
        <pubDate>Fri, 08 Sep 2017 18:07:49 GMT</pubDate>
        <generator>umbraco</generator>
        <description></description>
        <language>en</language>
        <atom:link rel="self" type="application/rss+xml" href="https://cultiv.nl/rss" />
            <item>
                <title>Help your favorite open source project by helping yourself</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/help-your-favorite-open-source-project-by-helping-yourself/</link>
                <pubDate>Fri, 08 Sep 2017 18:07:49 GMT</pubDate>
                <guid>https://cultiv.nl/blog/help-your-favorite-open-source-project-by-helping-yourself/</guid>
                <description>
                    <![CDATA[<p>Hello, my name is Sebastiaan and I work for <a href="https://umbraco.com">Umbraco</a>.</p>
<p>When I started working for Umbraco we had a large but manageable community of people building sites with Umbraco and figuring out the best solutions for their problems with our software. Problems? Yes, we have an approximately 15-year old codebase, which had many bugs when I started working at Umbraco we have many bugs we have yet to fix.</p>
<p>We used to be able to mostly keep up with bugs people were dealing with, we more often than not were able to give tips on the forums, on Twitter and in the issue tracker. This is fun and thankful work and I still love helping out whenever I can.</p>
<p>However, these days, with the amount of people using our software, this is no longer manageable. Many people want to use our software and this is great. I still love to help people but I can't dive into every problem in depth, nor can my colleagues. This is why we offer support contracts, if you need help and you're willing to pay for it then you get to jump the line of people who also want help but are not willing to pay for it.. or not able to pay for it. Your money allows us to hire and train more people to help out!</p>
<p>But that last category of people, the ones that simply cannot pay for priority support are sometimes out of luck. We have a <a href="https://our.umbraco.org/">wonderful community</a>, donating a lot of their spare time to try and help out. But their time is also limited and they will not always be able to give you a solution either. </p>
<p>Most of the time we will spend the time to pick up high priority problems that affect a lot of Umbraco users anyway, so most people are not left high and dry when there's bad bugs.</p>
<p>On the other hand, the problem you're facing might only apply to you, or it has a workaround that's acceptable to most people or it only applies to a particular setup that we are unable to replicate. What to do?</p>
<h2>Contributing to open source software</h2>
<p>As a developer myself, I use open source tools that help me do my job better or easier. I often get annoyed or blocked by some bug in the software. So, I like giving back!</p>
<p><img style="width: 289px; height: 340px;" src="https://cultiv.nl/media/8424/2017-09-08_202249.png?width=289&amp;height=340" alt="" data-id="1917"></p>
<p>Over the years I've contributed to projects like Git Extensions, lets-encrypt-win-simple, ACMESharp, ImageProcessor, UmbracoTracelogViewer and other projects. Some of these were directly related to work I was doing for Umbraco, most in my spare time.</p>
<p>And here is where I have a confession to make: most of my contributions initially were born out of pure frustration. Bugs that were annoying, features that didn't work the way I liked them, missing features, etc. So that's the dirty truth: I mostly contributed out of pure selfishness. </p>
<p>However, the happy outcome of these contributions has always been: a change for the better, not just for me but for all the other users of that software. It may come as no surprise but it feels really, REALLY good to help turn that frown upside down!</p>
<p><img style="width: 480px; height: 270px;" src="https://cultiv.nl/media/8425/frownupsidedown.gif?width=480&amp;height=270" alt="" data-id="1918"></p>
<h2>Help yourself</h2>
<p>So, dear Umbraco users, let me give you some tips on how you can help yourself (and help us in the process!). You are in the unique position to investigate your particular problem.</p>
<p>By digging into the specific bug you're encountering you can give us a hint or some proof of where our code is doing something wrong, You might even be able to send us a pull request so we can look at it and go "ha! how could we have been so silly as to believe that would ever work correctly?". After which we'll happily click the "Merge" button to get your code into the next release of Umbraco and you potentially make many people's life better!</p>
<p>Here are a few steps you should take:</p>
<h3>1. Identify the exact problem</h3>
<p>What exactly is happening?</p>
<p>It's like going to the doctor: if I press here, it hurts here. The better you can describe which steps you take to get into an unwanted situation, the better your chances that it can be fixed.</p>
<h3>2. Pinpoint the problem</h3>
<p>Following up to point 1: is it just you?</p>
<p>Download a fresh copy of the Umbraco version you're running and install it without any plugins and without your custom code in there. Follow the same steps you took to identify the problem (see point number 1). Do you still see the problem? If not, the problem is likely a configuration difference, due to some plugin you installed or caused by some of the custom code you wrote.</p>
<p>At this point I usually start to compare configuration files and if they're the same, I'd start taking some custom components out of the site, to see if I can narrow it down to some plugin or to some of my own code.</p>
<h3>3. Eliminate the problem</h3>
<p>Is the problem fixed already?</p>
<p>If you see an error message: Google it, add the word "Umbraco" in quotes to your query to get the best results. Is there an issue on the issue tracker with a "Due in version" set? Is the version higher than the version you're running now? Time to attempt an upgrade to see if the problem is already fixed! Take a backup of your site and database, upgrade the backup to the latest version and try steps 1 and 2 again.</p>
<p>Hint: issues on the tracker almost always point to the code we changed, it might give you a good idea of if your particular problem is going to be fixed.</p>
<h3>4. Investigate the problem</h3>
<p>Did none of the above help? Time to get your hands dirty! This is where the fun part starts! </p>
<p>Each Umbraco release <a href="https://github.com/umbraco/Umbraco-CMS/releases">is tagged when we release it</a>, so you can find the particular version you're using and get the exact source code for it. You can clone the Umbraco repository and with a command like `git checkout tags/release-7.4.2` you would get to the exact code that your Umbraco 7.4.2 site is using right now. </p>
<p>With that code, you can now do great things! Open up `umbraco.sln` in Visual Studio and build it. The build output will not only give you the same dlls you are using right now but also the pdb files, the symbols to debug the code.</p>
<p>If you go into the `~/src/Umbraco.Web.UI/bin` directory you can find the files that were just modified.</p>
<p><img style="width: 557px; height: 666px;" src="https://cultiv.nl/media/8426/2017-09-08_205928.png?width=557&amp;height=666" alt="" data-id="1919"></p>
<p>Go ahead and copy these files right into the problematic website. You now have full debugging capabilities for that website, while maintaining the exact functionality that was in our dlls in the first place! </p>
<p>Back in Visual Studio you can attach it to the process that is running your website, for example IISExpress (the easiest way) or the w3wp process.</p>
<p>Now you can set breakpoints in our code to narrow down that problem that's been annoying the heck out of you!</p>
<p><strong>Pro tip</strong> - if your problem only occurs on the live server and you cannot attach to the process to set breakpoints: add copious logging to the areas you suspect of having problems, update the dlls on your server with the new ones that add logging and see what you can find.</p>
<h3>5. Report back to us!</h3>
<p>Hopefully by now you will have figured out the root cause of your particular problem, or at least you got closer to it. You should be able to tell us in great detail (describing the previous steps in depth) what the problem is and maybe even how we could fix it.</p>
<p>At this point people sometimes feel like they've spent too much time on this already and tell us: the code in file x on line y is wrong; you should change it from a KiloJoule to a Pancake. <br>This doesn't really tell us very much though, you might be right but to us a KiloJoule doesn't look like a Pancake at all so we would love to hear the process that led you to this conclusion. The more details you can give the easier we can help get this fixed.</p>
<p>We <a href="https://our.umbraco.org/contribute/quick-start-guide/">love pull requests</a>, send us the fixed code so it's easy for us to look at it, get embarrassed about our silly mistake and accept that fix as quick as we can.</p>
<p>Hint: unit tests are a great way to prove your fix does what it says it does and doesn't break something else. Not required, but much appreciated.</p>
<p>If you can't provide a unit test: be as detailed as you can in your description.</p>
<h3>Avoiding rabbit holes</h3>
<p>Aha, now you have the power!</p>
<p><img style="width: 0px; height: 0px;" src="https://cultiv.nl/media/8428/hemanpower.gif?width=0&amp;height=0" alt="" data-id="1921"></p>
<p>Something you should be careful of: changing loads of code. We understand, more than anyone, that our code might make you angry, that it's all wrong and not following best practices. There are reasons for this. We are dealing with legacy code, some of it might go away soon. We have coding styles that you may hate, we understand (even within our team there's the constant <a href="https://marketplace.visualstudio.com/items?itemName=Shanewho.IHateRegions">I Hate #Regions</a> battle).</p>
<p>Rarely will we accept a code clean-up pull request. It is not very useful, and might lead to a refactor gone wrong which introduces subtle bugs. </p>
<p>We also know that you are really missing feature X and you know exactly how to build it and, by golly, you're doing it, sinking a month's worth of weekends into it, emerging with a beautiful pull request.</p>
<p>We understand, completely, but.. talk to us first! Please, before you go down a rabbit hole, discuss it first, open an <a href="http://issues.umbraco.org/issues">issue on the issue tracker</a>, describe what you want to do and make sure we want you to do it.</p>
<p>It is always a good idea to lobby for an issue/feature by asking around about it on Twitter and adding a discussion in the dedicated forum "<a href="https://our.umbraco.org/forum/contributing-to-umbraco-cms/">Contributing to Umbraco CMS</a>". This should give you a bit of an idea of how useful other people think your proposal is.</p>
<p>Remember: we can't put everything in Umbraco, some things are much more suitable for a plugin. We would love to guide you.</p>
<h2>Conclusion</h2>
<p>The power of open source software is that you can poke at it, you can look into everything that's happening behind the scenes and get and better understanding of a problem you're having. That understanding may even lead to a bugfix, which would be great. But if anything, it will teach you something and by poking at problems in our code, you're not just helping yourself grow, eventually you might also help someone else, or many people in the process. </p>
<p>The true power of OSS is that by being selfish and helping yourself, you can turn that frown upside down for many people. </p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Hello, my name is Sebastiaan and I work for <a href="https://umbraco.com">Umbraco</a>.</p>
<p>When I started working for Umbraco we had a large but manageable community of people building sites with Umbraco and figuring out the best solutions for their problems with our software. Problems? Yes, we have an approximately 15-year old codebase, which had many bugs when I started working at Umbraco we have many bugs we have yet to fix.</p>
<p>We used to be able to mostly keep up with bugs people were dealing with, we more often than not were able to give tips on the forums, on Twitter and in the issue tracker. This is fun and thankful work and I still love helping out whenever I can.</p>
<p>However, these days, with the amount of people using our software, this is no longer manageable. Many people want to use our software and this is great. I still love to help people but I can't dive into every problem in depth, nor can my colleagues. This is why we offer support contracts, if you need help and you're willing to pay for it then you get to jump the line of people who also want help but are not willing to pay for it.. or not able to pay for it. Your money allows us to hire and train more people to help out!</p>
<p>But that last category of people, the ones that simply cannot pay for priority support are sometimes out of luck. We have a <a href="https://our.umbraco.org/">wonderful community</a>, donating a lot of their spare time to try and help out. But their time is also limited and they will not always be able to give you a solution either. </p>
<p>Most of the time we will spend the time to pick up high priority problems that affect a lot of Umbraco users anyway, so most people are not left high and dry when there's bad bugs.</p>
<p>On the other hand, the problem you're facing might only apply to you, or it has a workaround that's acceptable to most people or it only applies to a particular setup that we are unable to replicate. What to do?</p>
<h2>Contributing to open source software</h2>
<p>As a developer myself, I use open source tools that help me do my job better or easier. I often get annoyed or blocked by some bug in the software. So, I like giving back!</p>
<p><img style="width: 289px; height: 340px;" src="https://cultiv.nl/media/8424/2017-09-08_202249.png?width=289&amp;height=340" alt="" data-id="1917"></p>
<p>Over the years I've contributed to projects like Git Extensions, lets-encrypt-win-simple, ACMESharp, ImageProcessor, UmbracoTracelogViewer and other projects. Some of these were directly related to work I was doing for Umbraco, most in my spare time.</p>
<p>And here is where I have a confession to make: most of my contributions initially were born out of pure frustration. Bugs that were annoying, features that didn't work the way I liked them, missing features, etc. So that's the dirty truth: I mostly contributed out of pure selfishness. </p>
<p>However, the happy outcome of these contributions has always been: a change for the better, not just for me but for all the other users of that software. It may come as no surprise but it feels really, REALLY good to help turn that frown upside down!</p>
<p><img style="width: 480px; height: 270px;" src="https://cultiv.nl/media/8425/frownupsidedown.gif?width=480&amp;height=270" alt="" data-id="1918"></p>
<h2>Help yourself</h2>
<p>So, dear Umbraco users, let me give you some tips on how you can help yourself (and help us in the process!). You are in the unique position to investigate your particular problem.</p>
<p>By digging into the specific bug you're encountering you can give us a hint or some proof of where our code is doing something wrong, You might even be able to send us a pull request so we can look at it and go "ha! how could we have been so silly as to believe that would ever work correctly?". After which we'll happily click the "Merge" button to get your code into the next release of Umbraco and you potentially make many people's life better!</p>
<p>Here are a few steps you should take:</p>
<h3>1. Identify the exact problem</h3>
<p>What exactly is happening?</p>
<p>It's like going to the doctor: if I press here, it hurts here. The better you can describe which steps you take to get into an unwanted situation, the better your chances that it can be fixed.</p>
<h3>2. Pinpoint the problem</h3>
<p>Following up to point 1: is it just you?</p>
<p>Download a fresh copy of the Umbraco version you're running and install it without any plugins and without your custom code in there. Follow the same steps you took to identify the problem (see point number 1). Do you still see the problem? If not, the problem is likely a configuration difference, due to some plugin you installed or caused by some of the custom code you wrote.</p>
<p>At this point I usually start to compare configuration files and if they're the same, I'd start taking some custom components out of the site, to see if I can narrow it down to some plugin or to some of my own code.</p>
<h3>3. Eliminate the problem</h3>
<p>Is the problem fixed already?</p>
<p>If you see an error message: Google it, add the word "Umbraco" in quotes to your query to get the best results. Is there an issue on the issue tracker with a "Due in version" set? Is the version higher than the version you're running now? Time to attempt an upgrade to see if the problem is already fixed! Take a backup of your site and database, upgrade the backup to the latest version and try steps 1 and 2 again.</p>
<p>Hint: issues on the tracker almost always point to the code we changed, it might give you a good idea of if your particular problem is going to be fixed.</p>
<h3>4. Investigate the problem</h3>
<p>Did none of the above help? Time to get your hands dirty! This is where the fun part starts! </p>
<p>Each Umbraco release <a href="https://github.com/umbraco/Umbraco-CMS/releases">is tagged when we release it</a>, so you can find the particular version you're using and get the exact source code for it. You can clone the Umbraco repository and with a command like `git checkout tags/release-7.4.2` you would get to the exact code that your Umbraco 7.4.2 site is using right now. </p>
<p>With that code, you can now do great things! Open up `umbraco.sln` in Visual Studio and build it. The build output will not only give you the same dlls you are using right now but also the pdb files, the symbols to debug the code.</p>
<p>If you go into the `~/src/Umbraco.Web.UI/bin` directory you can find the files that were just modified.</p>
<p><img style="width: 557px; height: 666px;" src="https://cultiv.nl/media/8426/2017-09-08_205928.png?width=557&amp;height=666" alt="" data-id="1919"></p>
<p>Go ahead and copy these files right into the problematic website. You now have full debugging capabilities for that website, while maintaining the exact functionality that was in our dlls in the first place! </p>
<p>Back in Visual Studio you can attach it to the process that is running your website, for example IISExpress (the easiest way) or the w3wp process.</p>
<p>Now you can set breakpoints in our code to narrow down that problem that's been annoying the heck out of you!</p>
<p><strong>Pro tip</strong> - if your problem only occurs on the live server and you cannot attach to the process to set breakpoints: add copious logging to the areas you suspect of having problems, update the dlls on your server with the new ones that add logging and see what you can find.</p>
<h3>5. Report back to us!</h3>
<p>Hopefully by now you will have figured out the root cause of your particular problem, or at least you got closer to it. You should be able to tell us in great detail (describing the previous steps in depth) what the problem is and maybe even how we could fix it.</p>
<p>At this point people sometimes feel like they've spent too much time on this already and tell us: the code in file x on line y is wrong; you should change it from a KiloJoule to a Pancake. <br>This doesn't really tell us very much though, you might be right but to us a KiloJoule doesn't look like a Pancake at all so we would love to hear the process that led you to this conclusion. The more details you can give the easier we can help get this fixed.</p>
<p>We <a href="https://our.umbraco.org/contribute/quick-start-guide/">love pull requests</a>, send us the fixed code so it's easy for us to look at it, get embarrassed about our silly mistake and accept that fix as quick as we can.</p>
<p>Hint: unit tests are a great way to prove your fix does what it says it does and doesn't break something else. Not required, but much appreciated.</p>
<p>If you can't provide a unit test: be as detailed as you can in your description.</p>
<h3>Avoiding rabbit holes</h3>
<p>Aha, now you have the power!</p>
<p><img style="width: 0px; height: 0px;" src="https://cultiv.nl/media/8428/hemanpower.gif?width=0&amp;height=0" alt="" data-id="1921"></p>
<p>Something you should be careful of: changing loads of code. We understand, more than anyone, that our code might make you angry, that it's all wrong and not following best practices. There are reasons for this. We are dealing with legacy code, some of it might go away soon. We have coding styles that you may hate, we understand (even within our team there's the constant <a href="https://marketplace.visualstudio.com/items?itemName=Shanewho.IHateRegions">I Hate #Regions</a> battle).</p>
<p>Rarely will we accept a code clean-up pull request. It is not very useful, and might lead to a refactor gone wrong which introduces subtle bugs. </p>
<p>We also know that you are really missing feature X and you know exactly how to build it and, by golly, you're doing it, sinking a month's worth of weekends into it, emerging with a beautiful pull request.</p>
<p>We understand, completely, but.. talk to us first! Please, before you go down a rabbit hole, discuss it first, open an <a href="http://issues.umbraco.org/issues">issue on the issue tracker</a>, describe what you want to do and make sure we want you to do it.</p>
<p>It is always a good idea to lobby for an issue/feature by asking around about it on Twitter and adding a discussion in the dedicated forum "<a href="https://our.umbraco.org/forum/contributing-to-umbraco-cms/">Contributing to Umbraco CMS</a>". This should give you a bit of an idea of how useful other people think your proposal is.</p>
<p>Remember: we can't put everything in Umbraco, some things are much more suitable for a plugin. We would love to guide you.</p>
<h2>Conclusion</h2>
<p>The power of open source software is that you can poke at it, you can look into everything that's happening behind the scenes and get and better understanding of a problem you're having. That understanding may even lead to a bugfix, which would be great. But if anything, it will teach you something and by poking at problems in our code, you're not just helping yourself grow, eventually you might also help someone else, or many people in the process. </p>
<p>The true power of OSS is that by being selfish and helping yourself, you can turn that frown upside down for many people. </p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Let&#39;s Encrypt on Windows revisited</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/lets-encrypt-on-windows-revisited/</link>
                <pubDate>Mon, 08 Aug 2016 07:21:34 GMT</pubDate>
                <guid>https://cultiv.nl/blog/lets-encrypt-on-windows-revisited/</guid>
                <description>
                    <![CDATA[<p>Back in March, I <a data-id="1650" href="https://cultiv.nl/blog/lets-encrypt-on-windows/" title="Let's Encrypt, on Windows">blogged about Let's Encrypt</a> and then I got busy doing other things. This weekend I had another look at the state of things for Windows and discovered that a few industrious people have been building some great things. The on tool I like very much is <a href="https://github.com/Lone-Coder/letsencrypt-win-simple">lets-encrypt-win-simple</a> (lews). This is a small command line application that accepts some parameters to make obtaining a certificate as easy as possible. It supports installing certs into IIS and can set up an automated renewal process as well.</p>
<p>The best part about lews is that I can read the source code and understand what's going on, hurrah for keeping it fairly simple! The second best part was that I could really quickly develop a plugin for it. What I wanted to do is to fully automate obtaining the certificate. Currently it's not yet possible for me to automate the install of the certificate but (at Umbraco) we're working at making that possible as well.</p>
<p>If you've read my previous blog post, you know that Let's Encrypt needs to verify that you own the domain you're trying to purchase a certificate for. Let's Encrypt tells you to put a file in your site with a verification token in it, that they can then read. I used to do this manually but it became tedious, so I <a href="https://gist.github.com/nul800sebastiaan/4999468e3097e2147d54c06daa8ffb26">wrote a quick ApiController</a> so I can just tell my site: create a file, in folder x with content y. One warning though: <strong>this is VERY insecure</strong>. I've only secured it with a secret token right now but if you post to this endpoint over http, your request can be intercepted and random files can be written to your website!</p>
<p>Right. A quick test <a href="https://www.getpostman.com/">with Postman</a> later and I'm confident that I can now automatically create the verification that Let's Encrypt needs.</p>
<p><img style="width: 700px; height:573.3629300776914px;" src="https://cultiv.nl/media/8416/2016-08-08_094519.png?width=700&amp;height=573.3629300776914" alt="" data-id="1847"></p>
<p>Now I need to tell lets-encrypt-win-simple (can we just rename this to Lewis?) how to use this endpoint. Lewis (there, I did it!) allows for plugins to be built, just make a class that inherits from `LetsEncrypt.ACME.Simple.Plugin` and implement the methods you get. I took a peak at their FTP plugin and borrowed some code from that one.</p>
<p>In order to show up in the lews dialog you need to implement a `public override void PrintMenu()` method that tells you something like: "X: press x for my plugin". Then you can handle the keypess in a HandleMenuResponse method that you override and in which you test if "X" has been pressed. That's it, we're in business! We can now do whatever we want.</p>
<p>A bit of code:</p>
<p><img style="width: 555px; height:131px;" src="https://cultiv.nl/media/8418/2016-08-08_095310.png?width=555&amp;height=131" alt="" data-id="1849"></p>
<p>Results in an extra menu option:</p>
<p><img style="width: 700px; height:366.0878447395301px;" src="https://cultiv.nl/media/8417/2016-08-08_095451.png?width=700&amp;height=366.0878447395301" alt="" data-id="1848"></p>
<p>The prompt here is a bit deceiving, but instead of giving it a host to get a certificate for, you enter one of the menu options.</p>
<p>The code then needs to create a target (basically: a hostname for which to create a certificate) and call the `Auto` method, passing in this target:</p>
<pre>    public override void HandleMenuResponse(string response, List targets)
    {
        if (response != "c".ToLowerInvariant()) return;

        var target = new Target
        {
            Host = "cork.nl",
            WebRootPath = string.Empty,
            PluginName = Name
        };

        Auto(target);
    }
</pre>
<p>Of course you wouldn't have hard coded domains in there, this is just a proof of concept to see if it works.</p>
<p>Then it get's really interesting, Lewis (I always imagine people with the name Lewis have a moustache) will look for a method called `CreateAuthorizationFile` which is where we can call our endpoint with the directory name to create and the contents of the authorization file:</p>
<pre>    public override void CreateAuthorizationFile(string answerPath, string fileContents)
    {
        const string token = "not_my_real_secret";
        var endpoint = new Uri("https://cork.nl/umbraco/api/Certificate/ValidationFile/");
        var directoryName = answerPath.Split('/').Last();
        var parameters = string.Format(
            "DirectoryName={0}&amp;FileContent={1}&amp;Token={2}", directoryName, fileContents, token);

        using (var web = new WebClient())
        {
            web.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
            web.UploadString(endpoint, parameters);
        }
    }
</pre>
<p> This makes Let's Encrypt happy and they send me a certificate!</p>
<p><img style="width: 700px; height:366.0878447395301px;" src="https://cultiv.nl/media/8419/2016-08-08_101543.png?width=700&amp;height=366.0878447395301" alt="" data-id="1850"></p>
<p>Though I am happy with this result, I do wish I could do all this with just a few command line switches so that I don't need to manually tell Lewis (it's sticky, isn't it!) what to do every time I start it. Full automation <a href="https://github.com/Lone-Coder/letsencrypt-win-simple/issues/151">is on their roadmap</a> and I've sent them <a href="https://github.com/Lone-Coder/letsencrypt-win-simple/pull/275">a simple pull request</a> to get started. For now, I'll work with my fork which has this logic in it already.</p>
<p>What's not covered in this post, is the `Install` method, in which you can code how exactly to install the certificate on your target server. You can get some inspiration from the built-in plugins for that of course!</p>
<p>All in all, I'm happy that things are moving fast on the Windows side of Let's Encrypt and we'll definitely have a bright and encrypted future ahead of us!</p>
<p> </p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Back in March, I <a data-id="1650" href="https://cultiv.nl/blog/lets-encrypt-on-windows/" title="Let's Encrypt, on Windows">blogged about Let's Encrypt</a> and then I got busy doing other things. This weekend I had another look at the state of things for Windows and discovered that a few industrious people have been building some great things. The on tool I like very much is <a href="https://github.com/Lone-Coder/letsencrypt-win-simple">lets-encrypt-win-simple</a> (lews). This is a small command line application that accepts some parameters to make obtaining a certificate as easy as possible. It supports installing certs into IIS and can set up an automated renewal process as well.</p>
<p>The best part about lews is that I can read the source code and understand what's going on, hurrah for keeping it fairly simple! The second best part was that I could really quickly develop a plugin for it. What I wanted to do is to fully automate obtaining the certificate. Currently it's not yet possible for me to automate the install of the certificate but (at Umbraco) we're working at making that possible as well.</p>
<p>If you've read my previous blog post, you know that Let's Encrypt needs to verify that you own the domain you're trying to purchase a certificate for. Let's Encrypt tells you to put a file in your site with a verification token in it, that they can then read. I used to do this manually but it became tedious, so I <a href="https://gist.github.com/nul800sebastiaan/4999468e3097e2147d54c06daa8ffb26">wrote a quick ApiController</a> so I can just tell my site: create a file, in folder x with content y. One warning though: <strong>this is VERY insecure</strong>. I've only secured it with a secret token right now but if you post to this endpoint over http, your request can be intercepted and random files can be written to your website!</p>
<p>Right. A quick test <a href="https://www.getpostman.com/">with Postman</a> later and I'm confident that I can now automatically create the verification that Let's Encrypt needs.</p>
<p><img style="width: 700px; height:573.3629300776914px;" src="https://cultiv.nl/media/8416/2016-08-08_094519.png?width=700&amp;height=573.3629300776914" alt="" data-id="1847"></p>
<p>Now I need to tell lets-encrypt-win-simple (can we just rename this to Lewis?) how to use this endpoint. Lewis (there, I did it!) allows for plugins to be built, just make a class that inherits from `LetsEncrypt.ACME.Simple.Plugin` and implement the methods you get. I took a peak at their FTP plugin and borrowed some code from that one.</p>
<p>In order to show up in the lews dialog you need to implement a `public override void PrintMenu()` method that tells you something like: "X: press x for my plugin". Then you can handle the keypess in a HandleMenuResponse method that you override and in which you test if "X" has been pressed. That's it, we're in business! We can now do whatever we want.</p>
<p>A bit of code:</p>
<p><img style="width: 555px; height:131px;" src="https://cultiv.nl/media/8418/2016-08-08_095310.png?width=555&amp;height=131" alt="" data-id="1849"></p>
<p>Results in an extra menu option:</p>
<p><img style="width: 700px; height:366.0878447395301px;" src="https://cultiv.nl/media/8417/2016-08-08_095451.png?width=700&amp;height=366.0878447395301" alt="" data-id="1848"></p>
<p>The prompt here is a bit deceiving, but instead of giving it a host to get a certificate for, you enter one of the menu options.</p>
<p>The code then needs to create a target (basically: a hostname for which to create a certificate) and call the `Auto` method, passing in this target:</p>
<pre>    public override void HandleMenuResponse(string response, List targets)
    {
        if (response != "c".ToLowerInvariant()) return;

        var target = new Target
        {
            Host = "cork.nl",
            WebRootPath = string.Empty,
            PluginName = Name
        };

        Auto(target);
    }
</pre>
<p>Of course you wouldn't have hard coded domains in there, this is just a proof of concept to see if it works.</p>
<p>Then it get's really interesting, Lewis (I always imagine people with the name Lewis have a moustache) will look for a method called `CreateAuthorizationFile` which is where we can call our endpoint with the directory name to create and the contents of the authorization file:</p>
<pre>    public override void CreateAuthorizationFile(string answerPath, string fileContents)
    {
        const string token = "not_my_real_secret";
        var endpoint = new Uri("https://cork.nl/umbraco/api/Certificate/ValidationFile/");
        var directoryName = answerPath.Split('/').Last();
        var parameters = string.Format(
            "DirectoryName={0}&amp;FileContent={1}&amp;Token={2}", directoryName, fileContents, token);

        using (var web = new WebClient())
        {
            web.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
            web.UploadString(endpoint, parameters);
        }
    }
</pre>
<p> This makes Let's Encrypt happy and they send me a certificate!</p>
<p><img style="width: 700px; height:366.0878447395301px;" src="https://cultiv.nl/media/8419/2016-08-08_101543.png?width=700&amp;height=366.0878447395301" alt="" data-id="1850"></p>
<p>Though I am happy with this result, I do wish I could do all this with just a few command line switches so that I don't need to manually tell Lewis (it's sticky, isn't it!) what to do every time I start it. Full automation <a href="https://github.com/Lone-Coder/letsencrypt-win-simple/issues/151">is on their roadmap</a> and I've sent them <a href="https://github.com/Lone-Coder/letsencrypt-win-simple/pull/275">a simple pull request</a> to get started. For now, I'll work with my fork which has this logic in it already.</p>
<p>What's not covered in this post, is the `Install` method, in which you can code how exactly to install the certificate on your target server. You can get some inspiration from the built-in plugins for that of course!</p>
<p>All in all, I'm happy that things are moving fast on the Windows side of Let's Encrypt and we'll definitely have a bright and encrypted future ahead of us!</p>
<p> </p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Visual Studio and Umbraco as a Service</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/visual-studio-and-umbraco-as-a-service/</link>
                <pubDate>Sat, 16 Apr 2016 11:08:14 GMT</pubDate>
                <guid>https://cultiv.nl/blog/visual-studio-and-umbraco-as-a-service/</guid>
                <description>
                    <![CDATA[<p>In working with <a href="http://umbraco.com/cloud">Umbraco as a Service</a> (UaaS), we often get askeded the question is how to work with it using Visual Studio (VS). The answer up until now <a href="https://our.umbraco.org/documentation/Umbraco-as-a-Service/Set-Up/Visual-Studio/">has been a rather manual process</a>. I always get a little annoyed when advising people to do something manually when I know it can be automated. Automation is difficult to get right though, so I've been hacking away at a little script for the longest time but was never happy with it, it always seemed to be a little "half way there but not really". However, a few weeks ago I had a breakthrough that gets close to what I personally like to experience to start working with VS. <strong>TL;DR;</strong> - if you don't care about the background story, just scroll down to the end of this post to see a short video and a download link for the setup script.</p>
<h3>Background</h3>
<p>First let me start with a note on how UaaS currently works. When you create a new project you get 2 websites: a development environment and a live environment. The development environment has a git clone URL so you can get the website down to your machine and start building locally.</p>
<p><img style="width: 500px; height: 159.54922894424672px;" src="https://cultiv.nl/media/8413/2016-04-16_160043.png?width=500&amp;height=159.54922894424672" alt="" data-id="1794"></p>
<p>Once you're happy with the results you push the "end result" back to the development site, check that it's all working as expected and then you can push your changes to the live website.</p>
<p>The reason I said "end result" is because this is what your cloned website will basically look like locally:</p>
<p><img style="width: 117px; height: 376px;" src="https://cultiv.nl/media/8408/2016-04-16_133153.png?width=117&amp;height=376" alt="" data-id="1789"></p>
<p>You will note that there's a distinct lack of Visual Studio files, nor is there any code folders in there. In the UaaS documentation we refer to this as our "deployment repository".</p>
<p>When we started building Umbraco as a Service we of course had lofty goals of supporting all types of projects that could "just" be pushed to UaaS and we would take care of the rest. The option above is ONE of the possible options we worked on and currently the only one. It's the most simple one: give us an "end result" website and we'll make sure it works on UaaS.</p>
<p>Of course when you have lofty goals, at some point reality will catch up on you.. which it did for us. After all kinds of experiments with VS solutions in the git repository and Grunt/Gulp/Bower/Npm/etc. we realized that this would take significant extra effort to make work well. There were many other aspects around the automation experience that we would have to focus on as well, for example:</p>
<ul>
<li>The <a href="https://our.umbraco.org/documentation/Umbraco-as-a-Service/Getting-Started/Baselines/">baseline feature</a> (which complicates things if you start throwing in VS solutions, and javascript package managers)</li>
<li>Server resources; if UaaS starts being a build server, we need many more resources to be able to do this acceptably fast</li>
<li>Reliability; we need to make sure that all kinds of build setups work and run, we need to install pre-requisite software for that</li>
<li>Speaking of reliability: eventually builds will fail, so we'll need to build ways to debug, try again, clean up etc.</li>
</ul>
<p>We're a small team and don't have infinite resource to do all of this right now. We very much wish to still offer more advanced deployments but we have to choose to keep it simple for now. I think we currently have a happy medium on top of which we can build over time.</p>
<p>So, for now, we have a requirement that says: if you're a Visual Studio gal or guy, we ask you kindly to build things locally and drop it into the UaaS repository all pre-built. You can verify that it works on your local machine, at which point you can also be confident it works on UaaS once you push those changes up. This is what I mean when I say you push the "end result" up to UaaS (and why it's referred to as a "deploy repository" in our documentation).</p>
<p>This does mean that you're responsible for setting up your own VS environment and you will need to put your custom code in a different source control repository from the one on UaaS. The disadvantage is obvious, you're still going to be responsible for a small part of the infrastructure. Luckily it's easy to outsource that part to Github/Bitbucket/etc these days.</p>
<p>There is also a big advantage of this separation: it will force you to make your code more or less modular which means that you could end up dropping the same code into a different site and it will mostly "just" work. It might just teach you to blur the lines a little less and think more of separation of concerns.</p>
<h3>Automating the setup</h3>
<p>Okay, enough talk about how we got here, let's take away my one big annoyance: having to think about how to set up my VS solution. For the automation of this I've thought about how I would want to work: I want to have my website, it should automatically run from VS when I hit F5 and to make it simple, I want it to be a (VS) Website project. The reason to choose a Website project over a Web Application project is to make it reflect exactly what we're looking at, a web site in which we drop custom assets, like a dll with some code we want to add to the site.</p>
<p>So, not:</p>
<p><img style="width: 500px; height: 139.7058823529412px;" src="https://cultiv.nl/media/8409/2016-04-16_135537.png?width=500&amp;height=139.7058823529412" alt="" data-id="1790"></p>
<p>But:</p>
<p><img style="width: 500px; height: 133.08270676691728px;" src="https://cultiv.nl/media/8410/2016-04-16_135515.png?width=500&amp;height=133.08270676691728" alt="" data-id="1791"></p>
<p>Speaking of custom code, apart from the Website project I also want to have a (VS) Class library to write my code in that I can build and drop into the website's bin folder. This build and copy should happen automatically once I hit the Play button (debug button) in VS so that I can start putting in breakpoints and debug my code.</p>
<p>Here's where the biggest problem always was for me: I wanted to reference the <a href="https://www.nuget.org/packages/UmbracoCms.Core/">UmbracoCms.Core libraries</a> from the class library but I could never find a way to set up all the references in a reliable way. NuGet doesn't have a way to install the libraries from the command line either. Not having the references to UmbracoCms.Core would kind of defeat the purpose of automating this. "Hey, use this script to set it up. Oh and hey now you have to go and manually install the NuGet package after that, sorry!". </p>
<p>I finally accidentally <a href="https://github.com/uluhonolulu/BlogSamples/tree/master/NuGetSample">stumbled upon some code</a> from someone who managed to install NuGet packages from C# meaning it could now be fully automated!</p>
<h3>Team</h3>
<p>Alright, so where are we now: </p>
<ol>
<li>Create a new project on Umbraco as a Service</li>
<li>Download and run the Visual Studio automation script</li>
</ol>
<p>Tada! We have a UaaS site running in VS and we can immediately start being productive.</p>
<p><img style="width: 266px; height: 463px;" src="https://cultiv.nl/media/8412/2016-04-16_155934.png?width=266&amp;height=463" alt="" data-id="1793"></p>
<p><strong>Note:</strong> If you don't know what Puppy Monkey Baby is.. I am <a href="https://www.youtube.com/watch?v=ql7uY36-LwA">still confused too</a>.</p>
<p>That leaves us with one thing for which we don't have the optimal solution yet: sharing this with your team. Right now this is a bit harder then we want it to be due to the restrictions I told you about earlier in the "Background" section. But I think it's manageable for now. </p>
<p>We do try to help as much as we can though: while running the VS automation script, an empty git repository was also set up for you and a .gitignore file was added so you can start committing your new site immediately and push it to whichever git hosting you prefer. The ignore file will ignore anything that's going on in your deployment repository (the .Web folder, containing the "end result" site for UaaS).</p>
<p>So for a team member to get set up, you now have a 2-step process:</p>
<ol>
<li>git clone `your custom code repository`</li>
<li>git clone `UaaS git url` </li>
</ol>
<p>Conveniently, you also get a UaaSClone.cmd file in the root for that second step, so they don't have to go to the UaaS portal to go and find the git URL. They can just double click UaaSClone and go. The end result should look something like this:</p>
<p><img style="width: 165px; height: 144px;" src="https://cultiv.nl/media/8411/2016-04-16_154437.png?width=165&amp;height=144" alt="" data-id="1792"></p>
<p>So:</p>
<ul>
<li>Git repository for your custom code</li>
<li>NuGet packages folder for the packages installed into YourNameSpace.Core</li>
<li>YourNameSpace.Core - where your custom code goes</li>
<li>YourNameSpace.Web - the "end result" / deploy repository with the Umbraco website in it</li>
<li>Git Ignore file using a default Visual Studio ignore plus an added rule to ignore YourNameSpace.Web</li>
<li>The Visual Studio solution file</li>
<li>UaaSClone.cmd for your colleagues to execute to get a copy of YourNameSpace.Web in the correct place</li>
</ul>
<h3>Try it now </h3>
<p>So, without further ado: <a href="http://umbracoreleases.blob.core.windows.net/download/UaaS.cmd">download the batch file and start playing</a>.</p>
<p>You will need to enter the git clone URL that you can find in the UaaS portal for each of you projects and a namespace for Visual Studio. The process is captured in a video below (recommend watching in full screen and at least 720p to be able to read the text):</p>
<p><iframe width="700" height="394" src="https://www.youtube-nocookie.com/embed/qsWCxwB2560?rel=0&amp;showinfo=0" frameborder="0" allowfullscreen=""></iframe></p>
<p>Note that the script is something that has only just in the past few days fully materialized so there may be rough edges. We wanted to put this out there so people can have a play with it and we can receive feedback for the team to build on this. So please, provide us with feedback to make your experience better. Leave comments below!</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>In working with <a href="http://umbraco.com/cloud">Umbraco as a Service</a> (UaaS), we often get askeded the question is how to work with it using Visual Studio (VS). The answer up until now <a href="https://our.umbraco.org/documentation/Umbraco-as-a-Service/Set-Up/Visual-Studio/">has been a rather manual process</a>. I always get a little annoyed when advising people to do something manually when I know it can be automated. Automation is difficult to get right though, so I've been hacking away at a little script for the longest time but was never happy with it, it always seemed to be a little "half way there but not really". However, a few weeks ago I had a breakthrough that gets close to what I personally like to experience to start working with VS. <strong>TL;DR;</strong> - if you don't care about the background story, just scroll down to the end of this post to see a short video and a download link for the setup script.</p>
<h3>Background</h3>
<p>First let me start with a note on how UaaS currently works. When you create a new project you get 2 websites: a development environment and a live environment. The development environment has a git clone URL so you can get the website down to your machine and start building locally.</p>
<p><img style="width: 500px; height: 159.54922894424672px;" src="https://cultiv.nl/media/8413/2016-04-16_160043.png?width=500&amp;height=159.54922894424672" alt="" data-id="1794"></p>
<p>Once you're happy with the results you push the "end result" back to the development site, check that it's all working as expected and then you can push your changes to the live website.</p>
<p>The reason I said "end result" is because this is what your cloned website will basically look like locally:</p>
<p><img style="width: 117px; height: 376px;" src="https://cultiv.nl/media/8408/2016-04-16_133153.png?width=117&amp;height=376" alt="" data-id="1789"></p>
<p>You will note that there's a distinct lack of Visual Studio files, nor is there any code folders in there. In the UaaS documentation we refer to this as our "deployment repository".</p>
<p>When we started building Umbraco as a Service we of course had lofty goals of supporting all types of projects that could "just" be pushed to UaaS and we would take care of the rest. The option above is ONE of the possible options we worked on and currently the only one. It's the most simple one: give us an "end result" website and we'll make sure it works on UaaS.</p>
<p>Of course when you have lofty goals, at some point reality will catch up on you.. which it did for us. After all kinds of experiments with VS solutions in the git repository and Grunt/Gulp/Bower/Npm/etc. we realized that this would take significant extra effort to make work well. There were many other aspects around the automation experience that we would have to focus on as well, for example:</p>
<ul>
<li>The <a href="https://our.umbraco.org/documentation/Umbraco-as-a-Service/Getting-Started/Baselines/">baseline feature</a> (which complicates things if you start throwing in VS solutions, and javascript package managers)</li>
<li>Server resources; if UaaS starts being a build server, we need many more resources to be able to do this acceptably fast</li>
<li>Reliability; we need to make sure that all kinds of build setups work and run, we need to install pre-requisite software for that</li>
<li>Speaking of reliability: eventually builds will fail, so we'll need to build ways to debug, try again, clean up etc.</li>
</ul>
<p>We're a small team and don't have infinite resource to do all of this right now. We very much wish to still offer more advanced deployments but we have to choose to keep it simple for now. I think we currently have a happy medium on top of which we can build over time.</p>
<p>So, for now, we have a requirement that says: if you're a Visual Studio gal or guy, we ask you kindly to build things locally and drop it into the UaaS repository all pre-built. You can verify that it works on your local machine, at which point you can also be confident it works on UaaS once you push those changes up. This is what I mean when I say you push the "end result" up to UaaS (and why it's referred to as a "deploy repository" in our documentation).</p>
<p>This does mean that you're responsible for setting up your own VS environment and you will need to put your custom code in a different source control repository from the one on UaaS. The disadvantage is obvious, you're still going to be responsible for a small part of the infrastructure. Luckily it's easy to outsource that part to Github/Bitbucket/etc these days.</p>
<p>There is also a big advantage of this separation: it will force you to make your code more or less modular which means that you could end up dropping the same code into a different site and it will mostly "just" work. It might just teach you to blur the lines a little less and think more of separation of concerns.</p>
<h3>Automating the setup</h3>
<p>Okay, enough talk about how we got here, let's take away my one big annoyance: having to think about how to set up my VS solution. For the automation of this I've thought about how I would want to work: I want to have my website, it should automatically run from VS when I hit F5 and to make it simple, I want it to be a (VS) Website project. The reason to choose a Website project over a Web Application project is to make it reflect exactly what we're looking at, a web site in which we drop custom assets, like a dll with some code we want to add to the site.</p>
<p>So, not:</p>
<p><img style="width: 500px; height: 139.7058823529412px;" src="https://cultiv.nl/media/8409/2016-04-16_135537.png?width=500&amp;height=139.7058823529412" alt="" data-id="1790"></p>
<p>But:</p>
<p><img style="width: 500px; height: 133.08270676691728px;" src="https://cultiv.nl/media/8410/2016-04-16_135515.png?width=500&amp;height=133.08270676691728" alt="" data-id="1791"></p>
<p>Speaking of custom code, apart from the Website project I also want to have a (VS) Class library to write my code in that I can build and drop into the website's bin folder. This build and copy should happen automatically once I hit the Play button (debug button) in VS so that I can start putting in breakpoints and debug my code.</p>
<p>Here's where the biggest problem always was for me: I wanted to reference the <a href="https://www.nuget.org/packages/UmbracoCms.Core/">UmbracoCms.Core libraries</a> from the class library but I could never find a way to set up all the references in a reliable way. NuGet doesn't have a way to install the libraries from the command line either. Not having the references to UmbracoCms.Core would kind of defeat the purpose of automating this. "Hey, use this script to set it up. Oh and hey now you have to go and manually install the NuGet package after that, sorry!". </p>
<p>I finally accidentally <a href="https://github.com/uluhonolulu/BlogSamples/tree/master/NuGetSample">stumbled upon some code</a> from someone who managed to install NuGet packages from C# meaning it could now be fully automated!</p>
<h3>Team</h3>
<p>Alright, so where are we now: </p>
<ol>
<li>Create a new project on Umbraco as a Service</li>
<li>Download and run the Visual Studio automation script</li>
</ol>
<p>Tada! We have a UaaS site running in VS and we can immediately start being productive.</p>
<p><img style="width: 266px; height: 463px;" src="https://cultiv.nl/media/8412/2016-04-16_155934.png?width=266&amp;height=463" alt="" data-id="1793"></p>
<p><strong>Note:</strong> If you don't know what Puppy Monkey Baby is.. I am <a href="https://www.youtube.com/watch?v=ql7uY36-LwA">still confused too</a>.</p>
<p>That leaves us with one thing for which we don't have the optimal solution yet: sharing this with your team. Right now this is a bit harder then we want it to be due to the restrictions I told you about earlier in the "Background" section. But I think it's manageable for now. </p>
<p>We do try to help as much as we can though: while running the VS automation script, an empty git repository was also set up for you and a .gitignore file was added so you can start committing your new site immediately and push it to whichever git hosting you prefer. The ignore file will ignore anything that's going on in your deployment repository (the .Web folder, containing the "end result" site for UaaS).</p>
<p>So for a team member to get set up, you now have a 2-step process:</p>
<ol>
<li>git clone `your custom code repository`</li>
<li>git clone `UaaS git url` </li>
</ol>
<p>Conveniently, you also get a UaaSClone.cmd file in the root for that second step, so they don't have to go to the UaaS portal to go and find the git URL. They can just double click UaaSClone and go. The end result should look something like this:</p>
<p><img style="width: 165px; height: 144px;" src="https://cultiv.nl/media/8411/2016-04-16_154437.png?width=165&amp;height=144" alt="" data-id="1792"></p>
<p>So:</p>
<ul>
<li>Git repository for your custom code</li>
<li>NuGet packages folder for the packages installed into YourNameSpace.Core</li>
<li>YourNameSpace.Core - where your custom code goes</li>
<li>YourNameSpace.Web - the "end result" / deploy repository with the Umbraco website in it</li>
<li>Git Ignore file using a default Visual Studio ignore plus an added rule to ignore YourNameSpace.Web</li>
<li>The Visual Studio solution file</li>
<li>UaaSClone.cmd for your colleagues to execute to get a copy of YourNameSpace.Web in the correct place</li>
</ul>
<h3>Try it now </h3>
<p>So, without further ado: <a href="http://umbracoreleases.blob.core.windows.net/download/UaaS.cmd">download the batch file and start playing</a>.</p>
<p>You will need to enter the git clone URL that you can find in the UaaS portal for each of you projects and a namespace for Visual Studio. The process is captured in a video below (recommend watching in full screen and at least 720p to be able to read the text):</p>
<p><iframe width="700" height="394" src="https://www.youtube-nocookie.com/embed/qsWCxwB2560?rel=0&amp;showinfo=0" frameborder="0" allowfullscreen=""></iframe></p>
<p>Note that the script is something that has only just in the past few days fully materialized so there may be rough edges. We wanted to put this out there so people can have a play with it and we can receive feedback for the team to build on this. So please, provide us with feedback to make your experience better. Leave comments below!</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>An Umbraco database upgrade tip from the trenches</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/an-umbraco-database-upgrade-tip-from-the-trenches/</link>
                <pubDate>Wed, 06 Apr 2016 10:26:20 GMT</pubDate>
                <guid>https://cultiv.nl/blog/an-umbraco-database-upgrade-tip-from-the-trenches/</guid>
                <description>
                    <![CDATA[<p>Upon trying to help with an upgrade recently, I came across an interesting case: for some reason the site in question was impossible to upgrade, in the upgrade installer, the database upgrade would fail.</p>
<p>By chance, it took a long time to download the actual complete site they were trying to upgrade but I had the database backup on my machine already. Then it occurred to me: I don't really need the website, just the database!</p>
<p>Imagine you're upgrading from Umbraco 7.0.4 to 7.4.2, here's what you do (warning: blink and it's over!):</p>
<ul>
<li>Install a fresh copy of Umbraco 7.4.2 using SQL server</li>
<li>When it's done, go into your web.config and:
<ul>
<li>Change the version from 7.4.2 to 7.0.4
<ul>
<li>the Umbraco upgrade installer then knows: okay, I need to run <a data-id="1722" href="https://cultiv.nl/blog/using-umbraco-migrations-to-deploy-changes/" title="Using Umbraco migrations to deploy changes">every available migration</a> between versions 7.0.4 and 7.4.2</li>
</ul>
</li>
<li>Change the connection string to point to the database that you want to upgrade (the one that's still on version 7.0.4)</li>
</ul>
</li>
<li>Run the upgrade installer that kicks in automatically</li>
<li>Done!</li>
</ul>
<p>Of course you still need to upgrade the actual website with the new files and do your config merges etc, but at least you know that your custom code is not blocking the database upgrade any more.</p>
<p>Told you: blink and it's over!</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Upon trying to help with an upgrade recently, I came across an interesting case: for some reason the site in question was impossible to upgrade, in the upgrade installer, the database upgrade would fail.</p>
<p>By chance, it took a long time to download the actual complete site they were trying to upgrade but I had the database backup on my machine already. Then it occurred to me: I don't really need the website, just the database!</p>
<p>Imagine you're upgrading from Umbraco 7.0.4 to 7.4.2, here's what you do (warning: blink and it's over!):</p>
<ul>
<li>Install a fresh copy of Umbraco 7.4.2 using SQL server</li>
<li>When it's done, go into your web.config and:
<ul>
<li>Change the version from 7.4.2 to 7.0.4
<ul>
<li>the Umbraco upgrade installer then knows: okay, I need to run <a data-id="1722" href="https://cultiv.nl/blog/using-umbraco-migrations-to-deploy-changes/" title="Using Umbraco migrations to deploy changes">every available migration</a> between versions 7.0.4 and 7.4.2</li>
</ul>
</li>
<li>Change the connection string to point to the database that you want to upgrade (the one that's still on version 7.0.4)</li>
</ul>
</li>
<li>Run the upgrade installer that kicks in automatically</li>
<li>Done!</li>
</ul>
<p>Of course you still need to upgrade the actual website with the new files and do your config merges etc, but at least you know that your custom code is not blocking the database upgrade any more.</p>
<p>Told you: blink and it's over!</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Using Umbraco migrations to deploy changes</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/using-umbraco-migrations-to-deploy-changes/</link>
                <pubDate>Sun, 27 Mar 2016 11:03:24 GMT</pubDate>
                <guid>https://cultiv.nl/blog/using-umbraco-migrations-to-deploy-changes/</guid>
                <description>
                    <![CDATA[<p>In yesterday's blog post I boldly claimed that it's "just as easy" to create a custom table for a counter. Well, this is kinda true, kinda not true. It's really easy to go into your local SQL instance, create a table with two columns and use a bit of PetaPoco to insert or update it, this part is true. Then you have to deploy this change to your staging environment.. rinse, repeat. You will have to find a way to create that same table in an existing database. This gets harder when you don't have (easy) access to the database on the remote server.</p>
<p>This is where Umbraco migrations come in. Migrations were introduced in version 6 of Umbraco to help us change database schema's during an upgrade of Umbraco. Migrations use code instead of using SQL upgrade scripts, while scripts are nice they are limited to executing SQL. We realized that sometimes there's a need to execute some code during upgrades as well. For example: we sometimes want to migrate data that is difficult to handle in a SQL script but would be really easy to deal with using a bit of code.</p>
<p>As of Umbraco version 7.3 these migrations are also very useful for making schema changes in different environments by just deploying your code, no more need to write manual SQL scripts that need to run on each environment.</p>
<h3>How it works</h3>
<p>In the Umbraco database we have a table called umbracoMigration that tracks which migrations have ran for that specific database, so on a fresh 7.4.2 install you'd see the following:</p>
<p><img style="width: 500px; height: 172.52396166134187px;" src="https://cultiv.nl/media/8378/2016-03-27_131624.png?width=500&amp;height=172.52396166134187" alt="" data-id="1724"></p>
<p>When Umbraco starts, the first thing it does is that it gets the current version of Umbraco using `Umbraco.Core.Configuration.UmbracoVersion.Current` which in this case is 7.4.2 but when you update the Umbraco dlls to version 7.4.3 it will return 7.4.3. If Umbraco then cannot find the migration with name "Umbraco" and version "7.4.3" in the database, you will get the upgrade installer screen. </p>
<p><img style="width: 500px; height: 352.24274406332455px;" src="https://cultiv.nl/media/8379/2016-03-27_132200.png?width=500&amp;height=352.24274406332455" alt="" data-id="1725"></p>
<p>Once you click the Continue button Umbraco goes and finds all of the classes that have a `Migration` attribute with a version between the newest version in the `umbracoMigration` table and the `<span>Umbraco.Core.Configuration.UmbracoVersion.Current</span>` version. For example, if I've upgraded my Umbraco dlls from 7.3.5 to 7.4.2 it would find migrations targetting versions higher than 7.3.5 and lower than or equal to 7.4.2.</p>
<p><img style="width: 500px; height: 269.54976303317534px;" src="https://cultiv.nl/media/8380/2016-03-27_132402.png?width=500&amp;height=269.54976303317534" alt="" data-id="1726"></p>
<p>We don't do any migrations for patch releases, only for minor and major versions (remember a version is: major.minor.patch). So in reality the upgrade from 7.3.5 to 7.4.2 would only find migrations targeting version 7.4.0 like the ones above. After these have been executed, a new entry will appear in the `umbracoMigration` table, indicating the latest migration that ran on this database. For the Our Umbraco database, for example, you can see exactly which upgrades were done when:</p>
<p><img style="width: 352px; height: 248px;" src="https://cultiv.nl/media/8381/2016-03-27_133234.png?width=352&amp;height=248" alt="" data-id="1727"></p>
<p>The important part to understand about this is that when you deploy your website to the next environment, it will do this same comparison: find `Umbraco.Core.Configuration.UmbracoVersion.Current` and compare that to the highest migration in the `umbracoMigration` table. They will be different because the migration only ran on our local environment. You will again see the upgrade screen on your website, click continue and the migrations run on that environment after which the upgrade is complete. This means that any environment you deploy to will be consistent. </p>
<p><strong>Sidenote</strong>: we didn't always use to do this and people would often forget to run the upgrade installer after deploying their upgraded website from local to the next environment. Most times this wasn't a problem, but when there was actually changes to be made to the database they might have been forgotten, leading to an inconsistent database, leading to problems later on. This is also why you sometimes see database upgrade errors when these migrations run, at some point the proper changes were not made to your database years ago, leading to wrong assumptions on our end and an inability to upgrade your database.</p>
<h3>You too can do this</h3>
<p>Long story short: migrations are great! Now let's see how you can utilize them.</p>
<p>The table that I mentioned in my previous blog post could, for example) consist of a nodeId (a reference to a page in Umbraco) and a count (the number of times this page was visited). In this example we're going to be Umbraco's ORM called PetaPoco, and when using that, we can describe the table we want to use in a C# class like so:</p>
<pre> using Umbraco.Core.Persistence;<br><br> namespace Example.Models<br> {<br>   [TableName("Statistics")]<br>   [PrimaryKey("nodeId", autoIncrement = false)]<br>   public class Statistics<br>   {<br>     [Column("nodeId")]<br>     public int NodeId { get; set; }<br><br>     [Column("count")]<br>     public int Count { get; set; }<br>   }<br> }</pre>
<p>In order to build a migration, we can make a class that has the `Migration` attribute and inherits from `MigrationBase`. Inheriting from that requires you to implement the `Up()` and the `Down()` methods, for doing and upgrade and, if necessary, a downgrade.</p>
<pre>using Example.Models;<br>using Umbraco.Core;<br>using Umbraco.Core.Logging;<br>using Umbraco.Core.Persistence;<br>using Umbraco.Core.Persistence.Migrations;<br>using Umbraco.Core.Persistence.SqlSyntax;<br><br>namespace Example.Migrations<br>{<br>  [Migration("1.0.0", 1, "Statistics")]<br>  public class CreateStatisticsTable : MigrationBase<br>  {<br>    private readonly UmbracoDatabase _database = ApplicationContext.Current.DatabaseContext.Database;<br>    private readonly DatabaseSchemaHelper _schemaHelper;<br><br>    public CreateStatisticsTable(ISqlSyntaxProvider sqlSyntax, ILogger logger) <br>      : base(sqlSyntax, logger)<br>    {<br>      _schemaHelper = new DatabaseSchemaHelper(_database, logger, sqlSyntax);<br>    }<br><br>    public override void Up()<br>    {<br>      _schemaHelper.CreateTable&lt;Statistics&gt;(false);<br> <br>      // Remember you can execute ANY code here and in Down().. <br>      // Anything you can think of, go nuts (not really!)<br>    }<br><br>    public override void Down()<br>    {<br>      _schemaHelper.DropTable&lt;Statistics&gt;();<br>    }<br>  }<br>}</pre>
<p>The migration attribute needs to be provided with a version number, since we're just starting out this is set to "1.0.0". The next argument is the sort order, if there's multiple migrations necessary to upgrade to "Statistics" version 1.0.0 you can run them in the correct order. We use the `Statistics` class we created to describe the table earlier to create or drop the table.</p>
<p>Finally, we need to make this migration run. Since the attribute has the third argument "Statistics" it will not run and trigger when you upgrade Umbraco, only migrations with the name "Umbraco" run automatically. So we need to run it manually somehow. In the future we want to change Umbraco so that it also runs your custom migrations through the Umbraco upgrade installer, for now you'll need to handle it yourself.</p>
<p>In order to run this, we can create an EventHandler that runs when Umbraco starts. In this event handler we will look for the newest migration that ran for the "Statistics" product to check if we need to actually run any migrations. If the database tells us: version 1.0.0 of "Statistics" has been ran, we do nothing. If the version doesn't exist or is lower than the current version, we of course need to run the migration to get the database in a consistent state.</p>
<pre>using System;<br>using System.Linq;<br>using Semver;<br>using Umbraco.Core;<br>using Umbraco.Core.Logging;<br>using Umbraco.Core.Persistence.Migrations;<br>using Umbraco.Web;<br><br>namespace Example.Eventhandlers<br>{<br>  public class MigrationEvents : ApplicationEventHandler<br>  {<br>    protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)<br>    {<br>      HandleStatisticsMigration();<br>    }<br><br>    private static void HandleStatisticsMigration()<br>    {<br>      const string productName = "Statistics";<br>      var currentVersion = new SemVersion(0, 0, 0);<br><br>      // get all migrations for "Statistics" already executed<br>      var migrations = ApplicationContext.Current.Services.MigrationEntryService.GetAll(productName);<br><br>     // get the latest migration for "Statistics" executed<br>     var latestMigration = migrations.OrderByDescending(x =&gt; x.Version).FirstOrDefault();<br><br>     if (latestMigration != null)<br>       currentVersion = latestMigration.Version;<br><br>     var targetVersion = new SemVersion(1, 0, 0);<br>     if (targetVersion == currentVersion)<br>       return;<br><br>     var migrationsRunner = new MigrationRunner(<br>       ApplicationContext.Current.Services.MigrationEntryService,<br>       ApplicationContext.Current.ProfilingLogger.Logger,<br>       currentVersion,<br>       targetVersion,<br>       productName);<br><br>     try<br>     {<br>       migrationsRunner.Execute(UmbracoContext.Current.Application.DatabaseContext.Database);<br>     }<br>     catch (Exception e)<br>     {<br>       LogHelper.Error&lt;MigrationEvents&gt;("Error running Statistics migration", e);<br>     }<br>   }<br> }<br>}</pre>
<p><strong>Note:</strong> for versions before 7.4.2 you'll need to build in an extra `catch` as Umbraco was doing something silly, which is now fixed. So before the `catch (Exception e)` you can add a specific `catch`</p>
<pre>catch (System.Web.HttpException e)<br>{<br>  // because umbraco runs some other migrations after the migration runner <br>  // is executed we get httpexception<br>  // catch this error, but don't do anything<br>  // fixed in 7.4.2+ see : http://issues.umbraco.org/issue/U4-8077<br>}</pre>
<p>Cool, we now have a new table we can use and the migration has been noted for our local database. When we deploy this site, the migration will run again as it's not been recorded in that database yet.</p>
<p><img style="width: 500px; height: 286.63446054750403px;" src="https://cultiv.nl/media/8383/2016-03-27_141827.png?width=500&amp;height=286.63446054750403" alt="" data-id="1729"></p>
<p>Just as some code to test this I've added the counter to my Master template so it will execute on each page, it's not great architecture but it at least allows me to do some quick testing.</p>
<pre>@{<br>   Layout = null;<br><br>   var database = ApplicationContext.Current.DatabaseContext.Database;<br><br>   var query = new Sql()<br>       .Select("*")<br>       .From&lt;Statistics&gt;()<br>       .Where&lt;Statistics&gt;(x =&gt; x.NodeId == Model.Content.Id);<br><br>   var result = database.Fetch&lt;Statistics&gt;(query).FirstOrDefault();<br><br>   if (result == null)<br>   {<br>     database.Insert(new Statistics { NodeId = Model.Content.Id, Count = 1 });<br>   }<br>   else<br>   {<br>     result.Count = result.Count + 1;<br>     database.Update(result);<br>   }<br>}<br>&lt;span&gt;Views: @(result == null ? 1 : result.Count) - NodeId: @Model.Content.Id&lt;/span&gt;</pre>
<p>And after a few refreshes of the page I can see that this works like a charm.</p>
<p><img style="width: 500px; height: 277.39130434782606px;" src="https://cultiv.nl/media/8384/2016-03-27_142016.png?width=500&amp;height=277.39130434782606" alt="" data-id="1730"></p>
<p>And in our browser:</p>
<p><img style="width: 266px; height: 69px;" src="https://cultiv.nl/media/8386/2016-03-27_143920.png?width=266&amp;height=69" alt="" data-id="1732"></p>
<p>Now imagine you want to count things in different categories, like PageViews, Downloads, Clicks, etc. You can still use this table but you might want to add a category name to it so you can track different types of counters. </p>
<p>First, we can update our `Statistics` class and add the Category there. </p>
<pre>  [Column("category")]<br>  public string Category { get; set; }</pre>
<p>Then we can add a new migration that adds a column to the existing table.</p>
<pre>using Umbraco.Core.Logging;<br>using Umbraco.Core.Persistence.Migrations;<br>using Umbraco.Core.Persistence.SqlSyntax;<br><br>namespace Example.Migrations<br>{<br>  [Migration("1.0.1", 1, "Statistics")]<br>  public class AddCategoryToStatisticsTable : MigrationBase<br>  {<br>    public AddCategoryToStatisticsTable(ISqlSyntaxProvider sqlSyntax, ILogger logger) <br>      : base(sqlSyntax, logger)<br>    { }<br><br>    public override void Up()<br>    {<br>      Alter.Table("Statistics").AddColumn("Category").AsString().Nullable();<br>    }<br><br>    public override void Down()<br>    {<br>      Delete.Column("Category").FromTable("Statistics");<br>    }<br>  }<br>}</pre>
<p>The last thing we need to do is tell the EventHandler that we're expecting our "Statistics" product to be of a new version now, 1.0.1. Note that the migration above is also created to update the product to version 1.0.1.</p>
<pre>    var targetVersion = new SemVersion(1, 0, 1);</pre>
<p>When this runs we can see in the `umbracoMigration` table that, once again, the migration ran. We also see the new column on the `Statistics` table that we have there.</p>
<p><img id="__mcenew" src="https://cultiv.nl/media/8385/2016-03-27_143330.png" alt="" data-id="1731"></p>
<p>A quick update of our code now allows us to log the category of our counter as well.</p>
<pre>@using Example.Models<br>@using Umbraco.Core.Persistence<br>@inherits UmbracoTemplatePage<br>@{<br>   Layout = null;<br><br>   var database = ApplicationContext.Current.DatabaseContext.Database;<br>   var category = "PageView";<br><br>   var query = new Sql()<br>       .Select("*")<br>       .From&lt;Statistics&gt;()<br>       .Where&lt;Statistics&gt;(x =&gt; x.NodeId == Model.Content.Id &amp;&amp; x.Category == category);<br><br>   var result = database.Fetch&lt;Statistics&gt;(query).FirstOrDefault();<br><br>   if (result == null)<br>   {<br>     database.Insert(new Statistics { NodeId = Model.Content.Id, Count = 1, Category == category });<br>   }<br>   else<br>   {<br>     result.Count = result.Count + 1;<br>     database.Update(result);<br>   }<br>}<br>&lt;span&gt;Views: @(result == null ? 1 : result.Count) - NodeId: @Model.Content.Id&lt;/span&gt;</pre>
<h3>Conclusion</h3>
<p>This post was very much inspired by <a href="https://our.umbraco.org/forum/umbraco-as-a-service/75800-guide-for-custom-tables-in-uaas">a recent question on the forum and the answers there</a>, where I learned not to do this in a "hacky" way.</p>
<p>In this article we've seen that we can create migrations, "things" that need to be executed once on each environment that you deploy your website to. These "things" could be database tables, but you could also imagine that you might want to add a property to a document type, anything is possible. Migrations can help you make sure that all of your environments are in a consistent state when you deploy it to the next environment.</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>In yesterday's blog post I boldly claimed that it's "just as easy" to create a custom table for a counter. Well, this is kinda true, kinda not true. It's really easy to go into your local SQL instance, create a table with two columns and use a bit of PetaPoco to insert or update it, this part is true. Then you have to deploy this change to your staging environment.. rinse, repeat. You will have to find a way to create that same table in an existing database. This gets harder when you don't have (easy) access to the database on the remote server.</p>
<p>This is where Umbraco migrations come in. Migrations were introduced in version 6 of Umbraco to help us change database schema's during an upgrade of Umbraco. Migrations use code instead of using SQL upgrade scripts, while scripts are nice they are limited to executing SQL. We realized that sometimes there's a need to execute some code during upgrades as well. For example: we sometimes want to migrate data that is difficult to handle in a SQL script but would be really easy to deal with using a bit of code.</p>
<p>As of Umbraco version 7.3 these migrations are also very useful for making schema changes in different environments by just deploying your code, no more need to write manual SQL scripts that need to run on each environment.</p>
<h3>How it works</h3>
<p>In the Umbraco database we have a table called umbracoMigration that tracks which migrations have ran for that specific database, so on a fresh 7.4.2 install you'd see the following:</p>
<p><img style="width: 500px; height: 172.52396166134187px;" src="https://cultiv.nl/media/8378/2016-03-27_131624.png?width=500&amp;height=172.52396166134187" alt="" data-id="1724"></p>
<p>When Umbraco starts, the first thing it does is that it gets the current version of Umbraco using `Umbraco.Core.Configuration.UmbracoVersion.Current` which in this case is 7.4.2 but when you update the Umbraco dlls to version 7.4.3 it will return 7.4.3. If Umbraco then cannot find the migration with name "Umbraco" and version "7.4.3" in the database, you will get the upgrade installer screen. </p>
<p><img style="width: 500px; height: 352.24274406332455px;" src="https://cultiv.nl/media/8379/2016-03-27_132200.png?width=500&amp;height=352.24274406332455" alt="" data-id="1725"></p>
<p>Once you click the Continue button Umbraco goes and finds all of the classes that have a `Migration` attribute with a version between the newest version in the `umbracoMigration` table and the `<span>Umbraco.Core.Configuration.UmbracoVersion.Current</span>` version. For example, if I've upgraded my Umbraco dlls from 7.3.5 to 7.4.2 it would find migrations targetting versions higher than 7.3.5 and lower than or equal to 7.4.2.</p>
<p><img style="width: 500px; height: 269.54976303317534px;" src="https://cultiv.nl/media/8380/2016-03-27_132402.png?width=500&amp;height=269.54976303317534" alt="" data-id="1726"></p>
<p>We don't do any migrations for patch releases, only for minor and major versions (remember a version is: major.minor.patch). So in reality the upgrade from 7.3.5 to 7.4.2 would only find migrations targeting version 7.4.0 like the ones above. After these have been executed, a new entry will appear in the `umbracoMigration` table, indicating the latest migration that ran on this database. For the Our Umbraco database, for example, you can see exactly which upgrades were done when:</p>
<p><img style="width: 352px; height: 248px;" src="https://cultiv.nl/media/8381/2016-03-27_133234.png?width=352&amp;height=248" alt="" data-id="1727"></p>
<p>The important part to understand about this is that when you deploy your website to the next environment, it will do this same comparison: find `Umbraco.Core.Configuration.UmbracoVersion.Current` and compare that to the highest migration in the `umbracoMigration` table. They will be different because the migration only ran on our local environment. You will again see the upgrade screen on your website, click continue and the migrations run on that environment after which the upgrade is complete. This means that any environment you deploy to will be consistent. </p>
<p><strong>Sidenote</strong>: we didn't always use to do this and people would often forget to run the upgrade installer after deploying their upgraded website from local to the next environment. Most times this wasn't a problem, but when there was actually changes to be made to the database they might have been forgotten, leading to an inconsistent database, leading to problems later on. This is also why you sometimes see database upgrade errors when these migrations run, at some point the proper changes were not made to your database years ago, leading to wrong assumptions on our end and an inability to upgrade your database.</p>
<h3>You too can do this</h3>
<p>Long story short: migrations are great! Now let's see how you can utilize them.</p>
<p>The table that I mentioned in my previous blog post could, for example) consist of a nodeId (a reference to a page in Umbraco) and a count (the number of times this page was visited). In this example we're going to be Umbraco's ORM called PetaPoco, and when using that, we can describe the table we want to use in a C# class like so:</p>
<pre> using Umbraco.Core.Persistence;<br><br> namespace Example.Models<br> {<br>   [TableName("Statistics")]<br>   [PrimaryKey("nodeId", autoIncrement = false)]<br>   public class Statistics<br>   {<br>     [Column("nodeId")]<br>     public int NodeId { get; set; }<br><br>     [Column("count")]<br>     public int Count { get; set; }<br>   }<br> }</pre>
<p>In order to build a migration, we can make a class that has the `Migration` attribute and inherits from `MigrationBase`. Inheriting from that requires you to implement the `Up()` and the `Down()` methods, for doing and upgrade and, if necessary, a downgrade.</p>
<pre>using Example.Models;<br>using Umbraco.Core;<br>using Umbraco.Core.Logging;<br>using Umbraco.Core.Persistence;<br>using Umbraco.Core.Persistence.Migrations;<br>using Umbraco.Core.Persistence.SqlSyntax;<br><br>namespace Example.Migrations<br>{<br>  [Migration("1.0.0", 1, "Statistics")]<br>  public class CreateStatisticsTable : MigrationBase<br>  {<br>    private readonly UmbracoDatabase _database = ApplicationContext.Current.DatabaseContext.Database;<br>    private readonly DatabaseSchemaHelper _schemaHelper;<br><br>    public CreateStatisticsTable(ISqlSyntaxProvider sqlSyntax, ILogger logger) <br>      : base(sqlSyntax, logger)<br>    {<br>      _schemaHelper = new DatabaseSchemaHelper(_database, logger, sqlSyntax);<br>    }<br><br>    public override void Up()<br>    {<br>      _schemaHelper.CreateTable&lt;Statistics&gt;(false);<br> <br>      // Remember you can execute ANY code here and in Down().. <br>      // Anything you can think of, go nuts (not really!)<br>    }<br><br>    public override void Down()<br>    {<br>      _schemaHelper.DropTable&lt;Statistics&gt;();<br>    }<br>  }<br>}</pre>
<p>The migration attribute needs to be provided with a version number, since we're just starting out this is set to "1.0.0". The next argument is the sort order, if there's multiple migrations necessary to upgrade to "Statistics" version 1.0.0 you can run them in the correct order. We use the `Statistics` class we created to describe the table earlier to create or drop the table.</p>
<p>Finally, we need to make this migration run. Since the attribute has the third argument "Statistics" it will not run and trigger when you upgrade Umbraco, only migrations with the name "Umbraco" run automatically. So we need to run it manually somehow. In the future we want to change Umbraco so that it also runs your custom migrations through the Umbraco upgrade installer, for now you'll need to handle it yourself.</p>
<p>In order to run this, we can create an EventHandler that runs when Umbraco starts. In this event handler we will look for the newest migration that ran for the "Statistics" product to check if we need to actually run any migrations. If the database tells us: version 1.0.0 of "Statistics" has been ran, we do nothing. If the version doesn't exist or is lower than the current version, we of course need to run the migration to get the database in a consistent state.</p>
<pre>using System;<br>using System.Linq;<br>using Semver;<br>using Umbraco.Core;<br>using Umbraco.Core.Logging;<br>using Umbraco.Core.Persistence.Migrations;<br>using Umbraco.Web;<br><br>namespace Example.Eventhandlers<br>{<br>  public class MigrationEvents : ApplicationEventHandler<br>  {<br>    protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)<br>    {<br>      HandleStatisticsMigration();<br>    }<br><br>    private static void HandleStatisticsMigration()<br>    {<br>      const string productName = "Statistics";<br>      var currentVersion = new SemVersion(0, 0, 0);<br><br>      // get all migrations for "Statistics" already executed<br>      var migrations = ApplicationContext.Current.Services.MigrationEntryService.GetAll(productName);<br><br>     // get the latest migration for "Statistics" executed<br>     var latestMigration = migrations.OrderByDescending(x =&gt; x.Version).FirstOrDefault();<br><br>     if (latestMigration != null)<br>       currentVersion = latestMigration.Version;<br><br>     var targetVersion = new SemVersion(1, 0, 0);<br>     if (targetVersion == currentVersion)<br>       return;<br><br>     var migrationsRunner = new MigrationRunner(<br>       ApplicationContext.Current.Services.MigrationEntryService,<br>       ApplicationContext.Current.ProfilingLogger.Logger,<br>       currentVersion,<br>       targetVersion,<br>       productName);<br><br>     try<br>     {<br>       migrationsRunner.Execute(UmbracoContext.Current.Application.DatabaseContext.Database);<br>     }<br>     catch (Exception e)<br>     {<br>       LogHelper.Error&lt;MigrationEvents&gt;("Error running Statistics migration", e);<br>     }<br>   }<br> }<br>}</pre>
<p><strong>Note:</strong> for versions before 7.4.2 you'll need to build in an extra `catch` as Umbraco was doing something silly, which is now fixed. So before the `catch (Exception e)` you can add a specific `catch`</p>
<pre>catch (System.Web.HttpException e)<br>{<br>  // because umbraco runs some other migrations after the migration runner <br>  // is executed we get httpexception<br>  // catch this error, but don't do anything<br>  // fixed in 7.4.2+ see : http://issues.umbraco.org/issue/U4-8077<br>}</pre>
<p>Cool, we now have a new table we can use and the migration has been noted for our local database. When we deploy this site, the migration will run again as it's not been recorded in that database yet.</p>
<p><img style="width: 500px; height: 286.63446054750403px;" src="https://cultiv.nl/media/8383/2016-03-27_141827.png?width=500&amp;height=286.63446054750403" alt="" data-id="1729"></p>
<p>Just as some code to test this I've added the counter to my Master template so it will execute on each page, it's not great architecture but it at least allows me to do some quick testing.</p>
<pre>@{<br>   Layout = null;<br><br>   var database = ApplicationContext.Current.DatabaseContext.Database;<br><br>   var query = new Sql()<br>       .Select("*")<br>       .From&lt;Statistics&gt;()<br>       .Where&lt;Statistics&gt;(x =&gt; x.NodeId == Model.Content.Id);<br><br>   var result = database.Fetch&lt;Statistics&gt;(query).FirstOrDefault();<br><br>   if (result == null)<br>   {<br>     database.Insert(new Statistics { NodeId = Model.Content.Id, Count = 1 });<br>   }<br>   else<br>   {<br>     result.Count = result.Count + 1;<br>     database.Update(result);<br>   }<br>}<br>&lt;span&gt;Views: @(result == null ? 1 : result.Count) - NodeId: @Model.Content.Id&lt;/span&gt;</pre>
<p>And after a few refreshes of the page I can see that this works like a charm.</p>
<p><img style="width: 500px; height: 277.39130434782606px;" src="https://cultiv.nl/media/8384/2016-03-27_142016.png?width=500&amp;height=277.39130434782606" alt="" data-id="1730"></p>
<p>And in our browser:</p>
<p><img style="width: 266px; height: 69px;" src="https://cultiv.nl/media/8386/2016-03-27_143920.png?width=266&amp;height=69" alt="" data-id="1732"></p>
<p>Now imagine you want to count things in different categories, like PageViews, Downloads, Clicks, etc. You can still use this table but you might want to add a category name to it so you can track different types of counters. </p>
<p>First, we can update our `Statistics` class and add the Category there. </p>
<pre>  [Column("category")]<br>  public string Category { get; set; }</pre>
<p>Then we can add a new migration that adds a column to the existing table.</p>
<pre>using Umbraco.Core.Logging;<br>using Umbraco.Core.Persistence.Migrations;<br>using Umbraco.Core.Persistence.SqlSyntax;<br><br>namespace Example.Migrations<br>{<br>  [Migration("1.0.1", 1, "Statistics")]<br>  public class AddCategoryToStatisticsTable : MigrationBase<br>  {<br>    public AddCategoryToStatisticsTable(ISqlSyntaxProvider sqlSyntax, ILogger logger) <br>      : base(sqlSyntax, logger)<br>    { }<br><br>    public override void Up()<br>    {<br>      Alter.Table("Statistics").AddColumn("Category").AsString().Nullable();<br>    }<br><br>    public override void Down()<br>    {<br>      Delete.Column("Category").FromTable("Statistics");<br>    }<br>  }<br>}</pre>
<p>The last thing we need to do is tell the EventHandler that we're expecting our "Statistics" product to be of a new version now, 1.0.1. Note that the migration above is also created to update the product to version 1.0.1.</p>
<pre>    var targetVersion = new SemVersion(1, 0, 1);</pre>
<p>When this runs we can see in the `umbracoMigration` table that, once again, the migration ran. We also see the new column on the `Statistics` table that we have there.</p>
<p><img id="__mcenew" src="https://cultiv.nl/media/8385/2016-03-27_143330.png" alt="" data-id="1731"></p>
<p>A quick update of our code now allows us to log the category of our counter as well.</p>
<pre>@using Example.Models<br>@using Umbraco.Core.Persistence<br>@inherits UmbracoTemplatePage<br>@{<br>   Layout = null;<br><br>   var database = ApplicationContext.Current.DatabaseContext.Database;<br>   var category = "PageView";<br><br>   var query = new Sql()<br>       .Select("*")<br>       .From&lt;Statistics&gt;()<br>       .Where&lt;Statistics&gt;(x =&gt; x.NodeId == Model.Content.Id &amp;&amp; x.Category == category);<br><br>   var result = database.Fetch&lt;Statistics&gt;(query).FirstOrDefault();<br><br>   if (result == null)<br>   {<br>     database.Insert(new Statistics { NodeId = Model.Content.Id, Count = 1, Category == category });<br>   }<br>   else<br>   {<br>     result.Count = result.Count + 1;<br>     database.Update(result);<br>   }<br>}<br>&lt;span&gt;Views: @(result == null ? 1 : result.Count) - NodeId: @Model.Content.Id&lt;/span&gt;</pre>
<h3>Conclusion</h3>
<p>This post was very much inspired by <a href="https://our.umbraco.org/forum/umbraco-as-a-service/75800-guide-for-custom-tables-in-uaas">a recent question on the forum and the answers there</a>, where I learned not to do this in a "hacky" way.</p>
<p>In this article we've seen that we can create migrations, "things" that need to be executed once on each environment that you deploy your website to. These "things" could be database tables, but you could also imagine that you might want to add a property to a document type, anything is possible. Migrations can help you make sure that all of your environments are in a consistent state when you deploy it to the next environment.</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Making sure your Umbraco site performs on Azure</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/making-sure-your-umbraco-site-performs-on-azure/</link>
                <pubDate>Sat, 26 Mar 2016 10:00:14 GMT</pubDate>
                <guid>https://cultiv.nl/blog/making-sure-your-umbraco-site-performs-on-azure/</guid>
                <description>
                    <![CDATA[<p><a href="https://azure.microsoft.com/en-us/services/app-service/web/">Azure Web Apps</a> (previously known as Azure Websites) is an excellent service that can be used to host your Umbraco website in a cost effective way. I will not go into deploying your site to Azure, this is something that can be done in different ways and works exactly the same for Umbraco as it would work for any other ASP.NET website. Google it.</p>
<p>Instead, this post focuses on making sure your performance on Azure is optimized.</p>
<h3>Sync Examine indexes</h3>
<p>First and foremost there's something you need to understand about how the server structure is set up behind Azure Web Apps (AWA). The two most important servers in the setup are the Web Worker (the machine that has IIS on it which is hosting your site) and the File Server. Whenever a new website on AWA spins up, it gets assigned to a Web Worker which has enough capacity to run another web site on it, there may be dozens / hundreds of other sites running on it. Sometimes the Web Worker needs maintenance at which point your site will be re-allocated to another available Web Worker and your site will move there. I say "move" but there's one important thing to understand here: the files used in your website live on the File Server and not on the Web Worker. All that the Web Worker does is it sets up a network path (UNC path) and tells IIS: there you go, my files are here. This points to the File Server, not to a path on the local machine, even though a UNC path very much behaves like a local path.</p>
<p>Why is this important? One word: latency. Every time the Web Worker gets instructed to change a file on disk it has to reach out over a network connection to a different server and make that change. This is a relatively slow process. You will not notice this latency when doing "normal" operations like, for example, saving a template in Umbraco.</p>
<p>However, where you will notice this latency is when it comes to disk operations that need to be highly performant. One of the best examples here in both read and write latency are the Examine indexes. Umbraco comes with a Lucene.Net implementation called Examine and it is fast.. really fast. It can be this fast because it relies on speedy access to it's data, the stored indexes on disk. Each time you ask for a media item, a query gets sent off to Examine to find the media item quickly. Each time you save a document in Umbraco, the saved information gets sent into Examine to be indexed. Each time you build a custom Examine searcher and use it.. you get the idea.</p>
<p>So, long story short: you want your Examine indexes to live on the local disk of the Web Worker instead of on the remote File Server. This can be done as of Umbraco 7.2.8 by adding the following attribute to all of your indexers and searchers: useTempStorage="Sync".</p>
<p><strong>Update:</strong> it has come to my attention that, for now, it's best not to include <a href="https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web.UI/config/ExamineIndex.config#L12">the machine name in your ExamineIndex.config</a>, so if you've previously added that you might want to consider removing that for the time being. Note that your indexes will be rebuilt when you do this, so if this is a long process make sure to plan for some downtime. More information <a href="https://our.umbraco.org/forum/developers/extending-umbraco/74731-examine-corruption-issues#comment-243496">can be found in this forum topic</a>.</p>
<p>The 'Sync' setting will store your indexes in ASP.NET's temporary file folder which is on the local file system (so: on the Web Worker). Any time the index is updated, this setting will ensure that both the locally created indexes and the normal indexes are written to. This will ensure that when the app is restarted or the local (Web Worker) temp files are cleared out that the index files can be restored from the centrally stored index files (on the File Server). If you see issues with this syncing process (in your logs), you could change this value to be 'LocalOnly' which will only persist the index files to the local file system in ASP.Net temp files.</p>
<p>Setting the indexes to "Sync" will ensure that your websites starts as fast as it can after it's been moved to a new Web Worker, the indexes will be copied from the File Server to the Web Worker during application startup. If you set the setting to "LocalOnly" your indexes will only ever exist on the Web Workers and thus need to be rebuilt every time your site is moved to a new Web Worker. This could work just fine for most sites but there's no performance to be gained from it and if you have a large index, this may slow down your website on startup significantly as it needs to rebuild all of the indexes from scratch.</p>
<h3><span>FcnMode</span></h3>
<p>Shannon has written <a href="http://shazwazza.com/post/all-about-aspnet-file-change-notification-fcn/">an in-depth blog post about File Change Notifications</a> already so I'm not going to repeat that. We have shipped with `fcnMode="Single"` since Umbraco 7.3.5 and you should also set that attribute on your system.web/httpRuntime element in your web.config.</p>
<p>We have made this change to all of our Web Workers on <a href="http://umbraco.com/cloud">Umbraco as a Service</a> too and to quote Shannon from that blog post above:  </p>
<p><span class="quote">To solve this issue we changed fcnMode=”Single” in the machine.config so that all sites would effectively use “Single”… and the result was instant: No more constant app restarts, file server performance was instantly back to normal. And as far as I can tell, there has been no downside to running FCNMode in Single.</span></p>
<p>That blog post is now 6 months old and with ~2000 sites still happily running at great performance we're now confident that fcnMode="Single" is the only way to run any ASP.NET website. If you're on Umbraco versions older than 7.3.5, you can just add this attribute yourself, it will work on any version of Umbraco.</p>
<h3>Logs</h3>
<p>Umbraco uses Log4Net for logging debug information and errors. A few people with very active sites have found that the logger started slowing down the website so much it was easily noticeable and the performance hit could be tracked back to the logger. This occurred even though the logger was asynchronous and "shouldn't" have affected website performance. Since version 7.3.0 we've been shipping with a new logger that should take more of the stress off of your website. Even so, we do log a lot of information and all that logging can quickly start taking up a lot of disk space. </p>
<p>We recommend at least for your live website to set the Log Priority to "WARN" instead of the default "INFO" and when the site has been running well for a while and you're comfortable you could even swith to "ERROR".</p>
<h3>Debug</h3>
<p>It's your live environment. So what do you do in your web.config? Yes, indeed, you set debug mode to "false" and customErrors mode to "RemoteOnly". Right? Right! You also built your dlls in Release mode before deploying them, right? Right!</p>
<h3>What else</h3>
<p>Far be it for me to say that you might have produced some badly performing code. You're a professional programmer who has been at it for years and you know exactly what you're doing, right? Well on the off chance that you had a minor glitch in your brain, maybe you should check to make sure.</p>
<p>The biggest offense we see these days is people using <a href="https://our.umbraco.org/documentation/reference/management/services/">the ContentService and other Services</a> in their frontend queries. Please, please don't do this, it goes straight to the database and kills your performance, especially if you make queries as crazy as: find the root node and then query all of it's descendants (that's ALL nodes in Umbraco!) to find the property "thisIsAnAmazingArticle" and then ToList() it and show only the first article with this property set to true. Stop. :)</p>
<p>Another thing that seems to be a pattern (and it's certainly an anti-pattern) is that people make the exact same mistake that I once made for <a href="https://our.umbraco.org/">Our Umbraco</a>'s download section: I needed a download counter.. so, hey I know: let's add a property "counter" on each Download Document Type and save &amp; publish the Download page each time someone downloads this version, increase the counter with 1. Trust me, this doesn't scale. Ever. Please do not put counters on your document types and increase them programmatically. It's just as much work to create a simple table with a `nodeId` and `count` column and update that one with a bit of PetaPoco.</p>
<p>Caching can be super useful if you know that you need to do something that you can't optimize the performance of right now (or ever). Use Umbraco's Macro caching, or <a href="https://our.umbraco.org/documentation/reference/cache/updating-cache">Umbraco's ApplicationCache</a>, or implement <a href="http://mayflymedia.co.ukhttps://cultiv.nl/blog/tech-breakfast/mvc-donut-caching/">Donut Caching</a>, etc. Even a very short cache of a few minutes can make a world of difference if you have 10 requests per second doing the exact same work 10 times. Note, however, that caching really should be a last resort after you've tried to optimize as much as you can. With caching comes cache invalidation and that can be hard or <a href="http://www.forbes.com/sites/insertcoin/2015/12/25/steam-is-randomly-logging-users-into-other-peoples-accounts-and-exposing-their-information/#11c0891f68c5">even dangerous</a>.</p>
<p>Also, I won't JUST blame you: we have had some issues with Umbraco performance and some, let's say "interesting" bugs in older versions. Make sure to upgrade to the latest version of Umbraco that you can upgrade to. If you have to stick with patch upgrades then 7.2.8 and 7.3.8 are both considered stable, but if you can do minor upgrades, definitely consider going to at least 7.3.8. Of course if you like receiving regular update, then going to version 7.4.2 and keeping up with the latest versions would be much preferred (remember, I <a data-id="1679" href="https://cultiv.nl/blog/how-to-diagnose-umbraco-upgrade-problems/" title="How to diagnose Umbraco upgrade problems">blogged about upgrading Umbraco</a> recently as well).</p>
<p>Microsoft also makes mistakes, <a href="http://issues.umbraco.org/issue/U4-6338">this one is a pretty huge bug and you need to be aware of it</a> and manually install the patch if you're using Windows Server 2012R2.</p>
<h3>Conclusion</h3>
<p>This post is partly the result of <a href="https://our.umbraco.org/forum/umbraco-7/using-umbraco-7/72801-fixing-poor-performance-on-azure#comment-240446">questions and answers gathered over the last few months in this forum post</a>, it might be good to read through that to find some more specific examples that might apply to your situation. I hope this helps you optimize you Azure hosted Umbraco site (pro-tip: a lot of these tips also help on any other hosting provider). </p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p><a href="https://azure.microsoft.com/en-us/services/app-service/web/">Azure Web Apps</a> (previously known as Azure Websites) is an excellent service that can be used to host your Umbraco website in a cost effective way. I will not go into deploying your site to Azure, this is something that can be done in different ways and works exactly the same for Umbraco as it would work for any other ASP.NET website. Google it.</p>
<p>Instead, this post focuses on making sure your performance on Azure is optimized.</p>
<h3>Sync Examine indexes</h3>
<p>First and foremost there's something you need to understand about how the server structure is set up behind Azure Web Apps (AWA). The two most important servers in the setup are the Web Worker (the machine that has IIS on it which is hosting your site) and the File Server. Whenever a new website on AWA spins up, it gets assigned to a Web Worker which has enough capacity to run another web site on it, there may be dozens / hundreds of other sites running on it. Sometimes the Web Worker needs maintenance at which point your site will be re-allocated to another available Web Worker and your site will move there. I say "move" but there's one important thing to understand here: the files used in your website live on the File Server and not on the Web Worker. All that the Web Worker does is it sets up a network path (UNC path) and tells IIS: there you go, my files are here. This points to the File Server, not to a path on the local machine, even though a UNC path very much behaves like a local path.</p>
<p>Why is this important? One word: latency. Every time the Web Worker gets instructed to change a file on disk it has to reach out over a network connection to a different server and make that change. This is a relatively slow process. You will not notice this latency when doing "normal" operations like, for example, saving a template in Umbraco.</p>
<p>However, where you will notice this latency is when it comes to disk operations that need to be highly performant. One of the best examples here in both read and write latency are the Examine indexes. Umbraco comes with a Lucene.Net implementation called Examine and it is fast.. really fast. It can be this fast because it relies on speedy access to it's data, the stored indexes on disk. Each time you ask for a media item, a query gets sent off to Examine to find the media item quickly. Each time you save a document in Umbraco, the saved information gets sent into Examine to be indexed. Each time you build a custom Examine searcher and use it.. you get the idea.</p>
<p>So, long story short: you want your Examine indexes to live on the local disk of the Web Worker instead of on the remote File Server. This can be done as of Umbraco 7.2.8 by adding the following attribute to all of your indexers and searchers: useTempStorage="Sync".</p>
<p><strong>Update:</strong> it has come to my attention that, for now, it's best not to include <a href="https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web.UI/config/ExamineIndex.config#L12">the machine name in your ExamineIndex.config</a>, so if you've previously added that you might want to consider removing that for the time being. Note that your indexes will be rebuilt when you do this, so if this is a long process make sure to plan for some downtime. More information <a href="https://our.umbraco.org/forum/developers/extending-umbraco/74731-examine-corruption-issues#comment-243496">can be found in this forum topic</a>.</p>
<p>The 'Sync' setting will store your indexes in ASP.NET's temporary file folder which is on the local file system (so: on the Web Worker). Any time the index is updated, this setting will ensure that both the locally created indexes and the normal indexes are written to. This will ensure that when the app is restarted or the local (Web Worker) temp files are cleared out that the index files can be restored from the centrally stored index files (on the File Server). If you see issues with this syncing process (in your logs), you could change this value to be 'LocalOnly' which will only persist the index files to the local file system in ASP.Net temp files.</p>
<p>Setting the indexes to "Sync" will ensure that your websites starts as fast as it can after it's been moved to a new Web Worker, the indexes will be copied from the File Server to the Web Worker during application startup. If you set the setting to "LocalOnly" your indexes will only ever exist on the Web Workers and thus need to be rebuilt every time your site is moved to a new Web Worker. This could work just fine for most sites but there's no performance to be gained from it and if you have a large index, this may slow down your website on startup significantly as it needs to rebuild all of the indexes from scratch.</p>
<h3><span>FcnMode</span></h3>
<p>Shannon has written <a href="http://shazwazza.com/post/all-about-aspnet-file-change-notification-fcn/">an in-depth blog post about File Change Notifications</a> already so I'm not going to repeat that. We have shipped with `fcnMode="Single"` since Umbraco 7.3.5 and you should also set that attribute on your system.web/httpRuntime element in your web.config.</p>
<p>We have made this change to all of our Web Workers on <a href="http://umbraco.com/cloud">Umbraco as a Service</a> too and to quote Shannon from that blog post above:  </p>
<p><span class="quote">To solve this issue we changed fcnMode=”Single” in the machine.config so that all sites would effectively use “Single”… and the result was instant: No more constant app restarts, file server performance was instantly back to normal. And as far as I can tell, there has been no downside to running FCNMode in Single.</span></p>
<p>That blog post is now 6 months old and with ~2000 sites still happily running at great performance we're now confident that fcnMode="Single" is the only way to run any ASP.NET website. If you're on Umbraco versions older than 7.3.5, you can just add this attribute yourself, it will work on any version of Umbraco.</p>
<h3>Logs</h3>
<p>Umbraco uses Log4Net for logging debug information and errors. A few people with very active sites have found that the logger started slowing down the website so much it was easily noticeable and the performance hit could be tracked back to the logger. This occurred even though the logger was asynchronous and "shouldn't" have affected website performance. Since version 7.3.0 we've been shipping with a new logger that should take more of the stress off of your website. Even so, we do log a lot of information and all that logging can quickly start taking up a lot of disk space. </p>
<p>We recommend at least for your live website to set the Log Priority to "WARN" instead of the default "INFO" and when the site has been running well for a while and you're comfortable you could even swith to "ERROR".</p>
<h3>Debug</h3>
<p>It's your live environment. So what do you do in your web.config? Yes, indeed, you set debug mode to "false" and customErrors mode to "RemoteOnly". Right? Right! You also built your dlls in Release mode before deploying them, right? Right!</p>
<h3>What else</h3>
<p>Far be it for me to say that you might have produced some badly performing code. You're a professional programmer who has been at it for years and you know exactly what you're doing, right? Well on the off chance that you had a minor glitch in your brain, maybe you should check to make sure.</p>
<p>The biggest offense we see these days is people using <a href="https://our.umbraco.org/documentation/reference/management/services/">the ContentService and other Services</a> in their frontend queries. Please, please don't do this, it goes straight to the database and kills your performance, especially if you make queries as crazy as: find the root node and then query all of it's descendants (that's ALL nodes in Umbraco!) to find the property "thisIsAnAmazingArticle" and then ToList() it and show only the first article with this property set to true. Stop. :)</p>
<p>Another thing that seems to be a pattern (and it's certainly an anti-pattern) is that people make the exact same mistake that I once made for <a href="https://our.umbraco.org/">Our Umbraco</a>'s download section: I needed a download counter.. so, hey I know: let's add a property "counter" on each Download Document Type and save &amp; publish the Download page each time someone downloads this version, increase the counter with 1. Trust me, this doesn't scale. Ever. Please do not put counters on your document types and increase them programmatically. It's just as much work to create a simple table with a `nodeId` and `count` column and update that one with a bit of PetaPoco.</p>
<p>Caching can be super useful if you know that you need to do something that you can't optimize the performance of right now (or ever). Use Umbraco's Macro caching, or <a href="https://our.umbraco.org/documentation/reference/cache/updating-cache">Umbraco's ApplicationCache</a>, or implement <a href="http://mayflymedia.co.ukhttps://cultiv.nl/blog/tech-breakfast/mvc-donut-caching/">Donut Caching</a>, etc. Even a very short cache of a few minutes can make a world of difference if you have 10 requests per second doing the exact same work 10 times. Note, however, that caching really should be a last resort after you've tried to optimize as much as you can. With caching comes cache invalidation and that can be hard or <a href="http://www.forbes.com/sites/insertcoin/2015/12/25/steam-is-randomly-logging-users-into-other-peoples-accounts-and-exposing-their-information/#11c0891f68c5">even dangerous</a>.</p>
<p>Also, I won't JUST blame you: we have had some issues with Umbraco performance and some, let's say "interesting" bugs in older versions. Make sure to upgrade to the latest version of Umbraco that you can upgrade to. If you have to stick with patch upgrades then 7.2.8 and 7.3.8 are both considered stable, but if you can do minor upgrades, definitely consider going to at least 7.3.8. Of course if you like receiving regular update, then going to version 7.4.2 and keeping up with the latest versions would be much preferred (remember, I <a data-id="1679" href="https://cultiv.nl/blog/how-to-diagnose-umbraco-upgrade-problems/" title="How to diagnose Umbraco upgrade problems">blogged about upgrading Umbraco</a> recently as well).</p>
<p>Microsoft also makes mistakes, <a href="http://issues.umbraco.org/issue/U4-6338">this one is a pretty huge bug and you need to be aware of it</a> and manually install the patch if you're using Windows Server 2012R2.</p>
<h3>Conclusion</h3>
<p>This post is partly the result of <a href="https://our.umbraco.org/forum/umbraco-7/using-umbraco-7/72801-fixing-poor-performance-on-azure#comment-240446">questions and answers gathered over the last few months in this forum post</a>, it might be good to read through that to find some more specific examples that might apply to your situation. I hope this helps you optimize you Azure hosted Umbraco site (pro-tip: a lot of these tips also help on any other hosting provider). </p>]]>
                </content:encoded>
            </item>
            <item>
                <title>So you want to secure your Umbraco site</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/so-you-want-to-secure-your-umbraco-site/</link>
                <pubDate>Fri, 25 Mar 2016 11:31:32 GMT</pubDate>
                <guid>https://cultiv.nl/blog/so-you-want-to-secure-your-umbraco-site/</guid>
                <description>
                    <![CDATA[<p>Imagine, if you will, for a second, that you're trying to secure your Umbraco site by running it over an https connection, sounds complicated? Not so much. It's fairly trivial to set up once you have a certificate, which <a data-id="1650" href="https://cultiv.nl/blog/lets-encrypt-on-windows/" title="Let's Encrypt, on Windows">you now know how to create using Let's Encrypt</a>.</p>
<p>I'm not going to explain how to create a binding in IIS, this process is different per hosting provider and it's impossible to cover this for everyone. We've made it easy on <a href="http://umbraco.com/cloud">Umbraco as a Service</a> (UaaS): upload a .pfx file, bind it to one of your host names. We can (and will) make it even easier.</p>
<p>Alright, we're there, our site, when typing "https://" as the prefix works and gives us a satisfying green lock to show that the connection was encrypted end to end and Chrome tells us our site is secure, yay!</p>
<p><img style="width: 427.1186440677966px; height: 500px;" src="https://cultiv.nl/media/8361/2016-03-25_121607.png?width=427.1186440677966&amp;height=500" alt="" data-id="1695"></p>
<p>There's only one more thing that you need to do for Umbraco to make sure that the backoffice is secure: go into your web.config and find the appSetting called "umbracoUseSSL". This setting is "false" by default and needs to be changed to "true". A quick look in the source code of Umbraco teaches us that the only use for this setting is to make sure that the cookies issued when logging into the backoffice get the "secure" flag, meaning it will only send the cookie when the connection is encrypted (so only over https).</p>
<p>This is all it does, and that's all there is to it, you've secured your Umbraco site!</p>
<h2>Taking it further</h2>
<p>We're running successfully on https, but we might not be at the peak of our game yet, let's run some online scans to see what else we can do to make our site more secure.</p>
<h3>SSLLabs</h3>
<p>Okay, that was the good news. Full of hope you run over to <a href="https://www.ssllabs.com/ssltest/analyze.html">SSLLabs to test your site's security</a>. Depending on your hosting server's setup you might and come up with a.. disappointing grade. Luckily, my site lives on Umbraco as a Service, so I get a mighty fine "A" grade.</p>
<p><a href="https://www.ssllabs.com/ssltest/analyze.html?d=cork.nl"><img style="width: 500px; height: 240.1639344262295px;" src="https://cultiv.nl/media/8362/2016-03-25_122506.png?width=500&amp;height=240.1639344262295" alt="" data-id="1696"></a></p>
<p>Hoever, you might end up with a different grade if the server your hosting on has enabled insecure protocols and encryption ciphers. If you're self-hosting then I recommend you <a href="https://www.nartac.com/Products/IISCrypto">run Nartac IIS Crypto</a> and apply the fixes suggested using the "Best Practices" button. It's a dead-simple, one-click fix for most (if not all) of your bad grades on SSLLabs.</p>
<h3>HTTPS by default</h3>
<p>For the following modifications, I'm going to assume that <a href="http://www.iis.net/downloads/microsoft/url-rewrite">the URL Rewrite module for IIS</a> is installed on your webhosting server (exactly why Microsoft doesn't ship with this installed by default is beyond me!).</p>
<p>Now that we can access the site over HTTPS, let's redirect all traffic to the site to HTTPS, that way you always have that happy green lock in your browser and you will always encrypt all traffic against people trying to snoop on you whether they are a <a href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack">Man In The Middle</a>, your internet provider or the NSA. This can be done using a URL Rewrite rule. In the following rule "localhost" is excluded from rewriting so that I don't have to jump through hoops to set up valid certificates and hostnames when debugging my site on my local machine.</p>
<p>This configuration goes into the system.webServer/rewrite/rules section of the web.config:</p>
<pre> &lt;rule name="HTTP to HTTPS redirect" stopProcessing="true"&gt;<br>  &lt;match url="(.*)" /&gt;<br>  &lt;conditions&gt;<br>   &lt;add input="{HTTPS}" pattern="off" ignoreCase="true" /&gt;<br>   &lt;add input="{HTTP_HOST}" pattern="localhost" negate="true" /&gt;<br>  &lt;/conditions&gt;<br>  &lt;action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" /&gt;<br> &lt;/rule&gt;</pre>
<p>While we're adding redirects, it's good for search engines to have just one domain to look at, so I can set up a redirect that strips "www" from any requests (which will then feed into the rule above and makes sure to redirect to HTTPS):</p>
<pre> &lt;rule name="Strip www. from URL" stopProcessing="true"&gt;<br>  &lt;match url="^(.*)$" ignoreCase="true" /&gt;<br>  &lt;conditions logicalGrouping="MatchAll"&gt;<br>   &lt;add input="{HTTP_HOST}" pattern="^www\.(.+)$" /&gt;<br>  &lt;/conditions&gt;<br>  &lt;action type="Redirect" url="http://{C:1}/{R:1}" redirectType="Permanent" /&gt;<br> &lt;/rule&gt;</pre>
<p>To further minimize any attacks where bad guys might want to trick you into using insecure HTTP request, you can send up a header with each request called <a href="https://scotthelme.co.uk/hsts-the-missing-link-in-tls/">the HTTP Strict Transport Security (HSTS) header</a>. Enabling HSTS will tell the browser: for the specified amount of time you will not look up any pages on this domain over HTTP any more, always use HTTPS. This is an addition that can be made to the system.webServer/rewrite/outboundRules section:</p>
<pre> &lt;outboundRules&gt;<br>  &lt;rule name="Add Strict-Transport-Security when HTTPS" enabled="true"&gt;<br>  &lt;match serverVariable="RESPONSE_Strict_Transport_Security" pattern=".*" /&gt;<br>  &lt;conditions&gt;<br>   &lt;add input="{HTTPS}" pattern="on" ignoreCase="true" /&gt;<br>   &lt;add input="{HTTP_HOST}" pattern="localhost" negate="true" /&gt;<br>  &lt;/conditions&gt;<br>  &lt;action type="Rewrite" value="<span>max-age=63072000; includeSubDomains; preload</span>" /&gt;<br>  &lt;/rule&gt;<br> &lt;/outboundRules&gt;</pre>
<p>This adds the "Strict-Transport-Security" header that tells browsers: for the next 63072000 seconds (which is two years) the browser should not make any HTTP requests to this domain.</p>
<p><strong>Note:</strong> the rules for HSTS inclusion might change from time to time. Make sure to <a href="https://hstspreload.appspot.com/">read the current requirements</a> before you follow these steps.</p>
<p>However... there's still a tiny sliver of an attack vector here. If you are a <em>Man in the Middle</em> and manage to lure someone to a site that they've never visited before, their very first request will still be the only one ever to go over HTTP. In that single request the Man in the Middle could still possibly do bad things. The only way to eliminate this risk is to never allow HTTP connections to the site, but then everybody needs to know that you can only ever get to the site by prefixing it with "https://". Not very user friendly.</p>
<p>You can, however, ask to be put on a list that is baked into browsers like Chrome, Firefox, Safari, IE11 and Edge. This is called <a href="https://scotthelme.co.uk/hsts-preloading/">HSTS Preloading</a> and takes a few weeks to get set up (it's a manual process). When you do finally make it on this preloaded list, your browser will never request any pages over HTTP but choose HTTPS by default. Part of the manual check that Google will do is to see if HSTS is set up including subdomains and if the preload parameter is there, this is why they're added to the rewrite rule above.</p>
<p><img style="width: 500px; height: 414.42048517520215px;" src="https://cultiv.nl/media/8366/2016-03-25_143859.png?width=500&amp;height=414.42048517520215" alt="" data-id="1701"></p>
<h3>ASafaWeb</h3>
<p>The "Automated Security Analyser for ASP.NET Websites" will test your Umbraco site for known issues with ASP.NET websites. I'm not doing so well on this one and have a few things to fix.</p>
<p><img style="width: 500px; height: 335.30106257378986px;" src="https://cultiv.nl/media/8363/2016-03-25_123807.png?width=500&amp;height=335.30106257378986" alt="" data-id="1698"></p>
<p>AsafaWeb gives me excellent guidance to fix things like Custom Errors and an exposed Stack Trace, just update the web.config to set Custom Errors to "RemoteOnly" and we're good.</p>
<p>As for the orange warnings:</p>
<ul>
<li>Excessive headers: The header "Server: Microsoft-IIS/8.5" gets sent with each response. I have tried disabling this but apparently our UaaS servers forcefully add this header. Nothing I could do about it, this needs to be removed at a server level. There's many other ways to probe sites and find out (by looking at their behavior) that it's running IIS and even which version it runs. So attackers specifically out to target my site are only a few seconds extra delayed in picking the correct attack vectors, I'm not worried about this header.</li>
<li>HTTP only cookies: The "ARRAffinity" cookie is only there for IIS to quickly determine on which of the available web servers my website lives. It's not an attack vector: if it's wrong or doesn't exist, this cookie will just be overwritten with a new one.</li>
<li>Clickjacking: A valid concern, I can deny people framing my site with the simple addition of "X-Frame-Options" to the web.config (more on this later!). <br><strong>Note:</strong> Always make sure you remove a custom header first, if the webserver already has it's own "add" rule, then you can't overwrite it by inserting your own, you need to remove the existing one first. Also note that Umbraco has tried to be helpful and removed the header that tells the world what MVC version you're running by removing "X-Powered-By" in the systemWebserver/httpProtocol/customHeaders section of your web.config.<br>
<pre> &lt;httpProtocol&gt;<br>  &lt;customHeaders&gt;<br>   &lt;!-- Ensure the powered by header is not returned --&gt;<br>   &lt;remove name="X-Powered-By" /&gt;<br>   &lt;remove name="X-Frame-Options" /&gt;<br>   &lt;add name="X-Frame-Options" value="DENY" /&gt;<br>  &lt;/customHeaders&gt;<br> &lt;/httpProtocol&gt;</pre>
</li>
</ul>
<p>There's a few gray boxes there: because my site doesn't have a view state in the HTML, AsafaWeb assumes (correctly) that I'm not using WebForms, so those tests didn't need to run any further. I couldn't figure out how to trigger the "Hash dos patch" test, even after adding a form that does a POST (as described on AsafaWeb) it doesn't test for this problem. Luckily I know that UaaS runs on servers not affected by the <a href="http://technet.microsoft.com/en-us/security/bulletin/ms11-100" target="_blank">MS11-100</a> security vulnerability, but you might want to check with your hosting provider.</p>
<p>Looks better now:</p>
<p><img style="width: 500px; height: 107.18870346598203px;" src="https://cultiv.nl/media/8365/2016-03-25_130445.png?width=500&amp;height=107.18870346598203" alt="" data-id="1700"></p>
<h3>Security-headers.io</h3>
<p>Going even further down into securing our website, there's some "fun" things we can do to make most websites misbehave, <a href="http://www.troyhunt.com/2015/09/introducing-you-to-browser-security.html">like making it do the Harlem Shake</a>.</p>
<p><a href="https://securityheaders.io">Security-headers.io</a> looks to see if you've implemented policies to mitigate these kinds of problems which are mostly XSS (cross site scripting) based. Look at this result.. ouch:</p>
<p><img style="width: 500px; height: 452.8301886792453px;" src="https://cultiv.nl/media/8367/2016-03-25_144806.png?width=500&amp;height=452.8301886792453" alt="" data-id="1702"></p>
<p>We can easily makes this a lot better by following some of the advise here on adding a "X-Xss-Protection" and a "X-Content-Type-Options" header:</p>
<pre> &lt;httpProtocol&gt;<br>  &lt;customHeaders&gt;<br>   &lt;!-- Ensure the powered by header is not returned --&gt;<br>   &lt;remove name="X-Powered-By" /&gt;<br>   &lt;remove name="X-Frame-Options" /&gt;<br>   &lt;add name="X-Frame-Options" value="DENY" /&gt;<br>   &lt;remove name="X-Xss-Protection" /&gt;<br>   &lt;add name="X-Xss-Protection" value="1; mode=block" /&gt;<br>   &lt;remove name="X-Content-Type-Options" /&gt;<br>   &lt;add name="X-Content-Type-Options" value="nosniff" /&gt;<br>  &lt;/customHeaders&gt;<br> &lt;/httpProtocol&gt;</pre>
<p>Better:</p>
<p><img style="width: 500px; height: 213.2486388384755px;" src="https://cultiv.nl/media/8368/2016-03-25_145128.png?width=500&amp;height=213.2486388384755" alt="" data-id="1703"></p>
<p>The <a href="https://scotthelme.co.uk/content-security-policy-an-introduction/">Content Security Policy (CSP)</a> is a lot harder to implement because it requires you to look at all of your site's assets and whitelist them. This is difficult especially if you load video's from YouTube, use CDN hosted javascript libraries, links to external images etc. Which brings us to the following check to run.</p>
<h3>CSP Analyser</h3>
<p>The <a href="https://report-uri.io/home/analyse">CSP analyser over at report-uri.io</a> looks at any policies you've implemented and tells you how good they are. It's impossible to give a good policy for all websites, so I'll just post the one I've struggled with and finally landed on for this site:</p>
<pre> &lt;httpProtocol&gt;<br>  &lt;customHeaders&gt;<br>   &lt;!-- Ensure the powered by header is not returned --&gt;<br>   &lt;remove name="X-Powered-By" /&gt;<br>   &lt;remove name="X-Frame-Options" /&gt;<br>   &lt;add name="X-Frame-Options" value="DENY" /&gt;<br>   &lt;remove name="X-Xss-Protection" /&gt;<br>   &lt;add name="X-Xss-Protection" value="1; mode=block" /&gt;<br>   &lt;remove name="X-Content-Type-Options" /&gt;<br>   &lt;add name="X-Content-Type-Options" value="nosniff" /&gt;<br>   &lt;remove name="Content-Security-Policy" /&gt;<br>   &lt;add name="Content-Security-Policy" value="default-src 'self' https://www.gravatar.com;script-src 'self' https://www.google-analytics.com https://ssl.google-analytics.com;style-src 'self' 'sha256-MZKTI0Eg1N13tshpFaVW65co/LeICXq4hyVx6GWVlK0=' 'sha256-CwE3Bg0VYQOIdNAkbB/Btdkhul49qZuwgNCMPgNY5zw=' 'sha256-LpfmXS+4ZtL2uPRZgkoR29Ghbxcfime/CsD/4w5VujE=' 'sha256-YJO/M9OgDKEBRKGqp4Zd07dzlagbB+qmKgThG52u/Mk=' https://fonts.googleapis.com;img-src 'self' data: https://www.gravatar.com https://www.google-analytics.com;font-src 'self' https://fonts.gstatic.com https://fonts.googleapis.com;" /&gt;<br>  &lt;/customHeaders&gt;<br> &lt;/httpProtocol&gt;</pre>
<p>I am using Gravatar images, Google Analytics and the Google Fonts API. The sha256 references are there to fix <a href="https://github.com/Modernizr/Modernizr/pull/1263">some things that Modernizr.js wants to execute</a>, which wouldn't otherwise be allowed, Chrome dev tools will tell you exactly what to add if this is a problem for you:</p>
<p><img style="width: 500px; height: 302.937576499388px;" src="https://cultiv.nl/media/8369/2016-03-25_150753.png?width=500&amp;height=302.937576499388" alt="" data-id="1704"></p>
<p>To make it a bit easier for you to manage, <a href="https://report-uri.io/register/">report-uri.io allows you to set up a free</a><a href="https://report-uri.io/register/"> account</a>. Using that, all CSP violations will be logged for you so you can have a look at updating your whitelist accordingly.</p>
<p>After setting up a CSP, securityheaders.io now reports a respectable "A" grade.</p>
<p><img style="width: 500px; height: 159.5744680851064px;" src="https://cultiv.nl/media/8370/2016-03-25_152221.png?width=500&amp;height=159.5744680851064" alt="" data-id="1705"></p>
<p>I've looked into <a href="https://scotthelme.co.uk/hpkp-http-public-key-pinning/">Public Key Pinning (HPKP)</a> but the process seems too onerous for little gain for now. The problem with HPKP is currently that I don't understand how backup CSRs are supposed to work and what exactly I need to do when my current certificate expires. I have done some experiments and they worked but I need to do further testing to see what it will take to switch to a new certificate.</p>
<p>In case you are wondering (and are brave), the HPKP header can be configured like so in system.webServer/httpProtocol/customHeaders:</p>
<pre> &lt;remove name="Public-Key-Pins" /&gt;<br> &lt;add name="Public-Key-Pins" value="max-age=31536000; pin-sha256=&amp;quot;h2EVK2+bga6XAxu7ImUQM0PJsgZd2/a2VtlcSmV87s4=&amp;quot;; pin-sha256=&amp;quot;9ilXj1leytbsCvXVIFJ1uzjmej2bzs05qzRzmfFzXKs=&amp;quot;; pin-sha256=&amp;quot;nupZBiNmjIMxIyEll+OBYjvMORUEyYTTr7K5bE2z7L0=&amp;quot;;" /&gt;</pre>
<p>Note that the double quotes need to be escaped because the web.config file is an XML file, so replace " with &amp;quot; everywhere in the value of this header.</p>
<h2>Back to Umbraco</h2>
<p>Now that we've made our frontend all nice and safe, let's go back into the backoffice of Umbraco.</p>
<p><img style="width: 500px; height: 364.5287958115183px;" src="https://cultiv.nl/media/8371/2016-03-25_153006.png?width=500&amp;height=364.5287958115183" alt="" data-id="1706"></p>
<p>Whoops, we broke it!</p>
<p>There's a few things going on in the backoffice that we need to allow now that we've disallowed a lot of them on the frontend. Umbraco still uses iframes for some pages in the backoffice so we'll need to allow those. The Content Security Policy is also blocking a lot of asset loading because they're set pretty strict on the frontend.</p>
<p>Luckily we don't have to change our frontend setup, we can just change the backoffice requirements a little bit. All the way at the bottom of our web.config we already have a &lt;location path="umbraco"&gt; section which tells IIS: for this location (the umbraco path) we want to apply different rules then for the rest of the site. We can amend this section with a custom CSP and allow frames from the same origin (so only frames with a location that lives somewhere in our site).</p>
<p>We're already disabling urlCompression for the backoffice as that can conflict with our backoffice javascripts, so let's add our updated headers there:</p>
<pre> &lt;location path="umbraco"&gt;<br>  &lt;system.webServer&gt;<br>   &lt;urlCompression doStaticCompression="false" doDynamicCompression="false" dynamicCompressionBeforeCache="false" /&gt;<br>   &lt;httpProtocol&gt;<br>    &lt;customHeaders&gt;<br>     &lt;remove name="X-Frame-Options" /&gt;<br>     &lt;add name="X-Frame-Options" value="SAMEORIGIN" /&gt;<br>     &lt;remove name="Content-Security-Policy" /&gt;<br>     &lt;add name="Content-Security-Policy" value="default-src 'self' www.gravatar.com player.vimeo.com *.vimeocdn.com packages.umbraco.org our.umbraco.org;script-src 'self' 'unsafe-inline' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' data: www.gravatar.com umbraco.tv;font-src 'self';" /&gt;<br>    &lt;/customHeaders&gt;<br>   &lt;/httpProtocol&gt; <br>  &lt;/system.webServer&gt;<br> &lt;/location&gt;</pre>
<p>Much better, our backoffice is back without errors.</p>
<p><img style="width: 500px; height: 419.89987484355447px;" src="https://cultiv.nl/media/8372/2016-03-25_154009.png?width=500&amp;height=419.89987484355447" alt="" data-id="1707"></p>
<p>One interesting thing I found when implementing CSP rules is that I was not allowed to have inline CSS in my site, this is a good thing, I don't want inline CSS, I want everything to be nicely tucked away in a CSS file.</p>
<p>One problem though: the rich text editor. When you insert an image in the RTE, Umbraco automatically adds an inline style for you with the dimensions of the image and there seems to be no way to prevent it from doing so. </p>
<p><img style="width: 500px; height: 384.7477064220183px;" src="https://cultiv.nl/media/8373/2016-03-25_160051.png?width=500&amp;height=384.7477064220183" alt="" data-id="1708"></p>
<p>I've created a simple extension method that goes through your html and strips out those inline styles. This StringExtensions.cs can be dropped into your App_Code folder:</p>
<pre>using System.Web;<br>using HtmlAgilityPack;<br><br>namespace Cultiv.StringExtensions<br>{<br>  public static class RteStyles<br>  {<br>    public static IHtmlString RemoveInlineImageStyles(this string text) <br>    {<br>      var htmlString = new HtmlString(text);<br>      return htmlString.RemoveInlineImageStyles();<br>    }<br> <br>    public static IHtmlString RemoveInlineImageStyles(this IHtmlString htmlString)<br>    {<br>      var htmlDocument = new HtmlDocument();<br>      htmlDocument.LoadHtml(htmlString.ToString());<br>      if(htmlDocument == null || htmlDocument.DocumentNode == null || htmlDocument.DocumentNode.SelectNodes("//img[@style]") == null) <br>      {<br>        return htmlString;<br>      }<br>      else<br>      {<br>        foreach (var node in htmlDocument.DocumentNode.SelectNodes("//img[@style]"))<br>        {<br>          var attribute = node.Attributes["style"];<br>          node.Attributes.Remove("style");<br>        }<br>      }<br>      return new HtmlString(htmlDocument.DocumentNode.OuterHtml);<br>    }<br>  }<br>}</pre>
<p>I use it as follows in my templates:</p>
<pre>@(Model.Content.GetPropertyValue&lt;string&gt;("bodyText").RemoveInlineImageStyles())</pre>
<h2>Conclusion</h2>
<p>Security is hard. :-)</p>
<p>Luckily there's plenty of tools that help ease the pain. We are always looking into updating Umbraco where possible to take away the pain by setting up sensible defaults. We're also working on making things easier to set up on Umbraco as a Service where we can rely more on automation.</p>
<p>There's a few security related sites I should point to that are excellent in helping you understand security and keeping you safe:</p>
<ul>
<li>Follow <a href="http://www.troyhunt.com/">Troy Hunt's blog</a> and <a href="https://twitter.com/troyhunt">Twitter account</a> (or whatever social media you like, there's plenty of icons on his site)
<ul>
<li>If you have a PluralSight account, <a href="http://app.pluralsight.com/author/troy-hunt">his security courses are always great</a> as well </li>
</ul>
</li>
<li>Follow <a href="https://scotthelme.co.uk/">Scott Helme's blog</a> and <a href="https://twitter.com/Scott_Helme/">Twitter account</a></li>
<li>I enjoy <a href="https://twit.tv/shows/security-now">the Security Now podcast</a> for regular in depth discussions of how security works (and most notably: where it fails, of course) and recommend playing it at 1.5 speed</li>
</ul>
<p>Finally: there's a lot more you can do to protect your site, but this is a mammoth post already so I'll end this here in hopes that I get more time in the future to cover related topics.</p>
<p> </p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Imagine, if you will, for a second, that you're trying to secure your Umbraco site by running it over an https connection, sounds complicated? Not so much. It's fairly trivial to set up once you have a certificate, which <a data-id="1650" href="https://cultiv.nl/blog/lets-encrypt-on-windows/" title="Let's Encrypt, on Windows">you now know how to create using Let's Encrypt</a>.</p>
<p>I'm not going to explain how to create a binding in IIS, this process is different per hosting provider and it's impossible to cover this for everyone. We've made it easy on <a href="http://umbraco.com/cloud">Umbraco as a Service</a> (UaaS): upload a .pfx file, bind it to one of your host names. We can (and will) make it even easier.</p>
<p>Alright, we're there, our site, when typing "https://" as the prefix works and gives us a satisfying green lock to show that the connection was encrypted end to end and Chrome tells us our site is secure, yay!</p>
<p><img style="width: 427.1186440677966px; height: 500px;" src="https://cultiv.nl/media/8361/2016-03-25_121607.png?width=427.1186440677966&amp;height=500" alt="" data-id="1695"></p>
<p>There's only one more thing that you need to do for Umbraco to make sure that the backoffice is secure: go into your web.config and find the appSetting called "umbracoUseSSL". This setting is "false" by default and needs to be changed to "true". A quick look in the source code of Umbraco teaches us that the only use for this setting is to make sure that the cookies issued when logging into the backoffice get the "secure" flag, meaning it will only send the cookie when the connection is encrypted (so only over https).</p>
<p>This is all it does, and that's all there is to it, you've secured your Umbraco site!</p>
<h2>Taking it further</h2>
<p>We're running successfully on https, but we might not be at the peak of our game yet, let's run some online scans to see what else we can do to make our site more secure.</p>
<h3>SSLLabs</h3>
<p>Okay, that was the good news. Full of hope you run over to <a href="https://www.ssllabs.com/ssltest/analyze.html">SSLLabs to test your site's security</a>. Depending on your hosting server's setup you might and come up with a.. disappointing grade. Luckily, my site lives on Umbraco as a Service, so I get a mighty fine "A" grade.</p>
<p><a href="https://www.ssllabs.com/ssltest/analyze.html?d=cork.nl"><img style="width: 500px; height: 240.1639344262295px;" src="https://cultiv.nl/media/8362/2016-03-25_122506.png?width=500&amp;height=240.1639344262295" alt="" data-id="1696"></a></p>
<p>Hoever, you might end up with a different grade if the server your hosting on has enabled insecure protocols and encryption ciphers. If you're self-hosting then I recommend you <a href="https://www.nartac.com/Products/IISCrypto">run Nartac IIS Crypto</a> and apply the fixes suggested using the "Best Practices" button. It's a dead-simple, one-click fix for most (if not all) of your bad grades on SSLLabs.</p>
<h3>HTTPS by default</h3>
<p>For the following modifications, I'm going to assume that <a href="http://www.iis.net/downloads/microsoft/url-rewrite">the URL Rewrite module for IIS</a> is installed on your webhosting server (exactly why Microsoft doesn't ship with this installed by default is beyond me!).</p>
<p>Now that we can access the site over HTTPS, let's redirect all traffic to the site to HTTPS, that way you always have that happy green lock in your browser and you will always encrypt all traffic against people trying to snoop on you whether they are a <a href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack">Man In The Middle</a>, your internet provider or the NSA. This can be done using a URL Rewrite rule. In the following rule "localhost" is excluded from rewriting so that I don't have to jump through hoops to set up valid certificates and hostnames when debugging my site on my local machine.</p>
<p>This configuration goes into the system.webServer/rewrite/rules section of the web.config:</p>
<pre> &lt;rule name="HTTP to HTTPS redirect" stopProcessing="true"&gt;<br>  &lt;match url="(.*)" /&gt;<br>  &lt;conditions&gt;<br>   &lt;add input="{HTTPS}" pattern="off" ignoreCase="true" /&gt;<br>   &lt;add input="{HTTP_HOST}" pattern="localhost" negate="true" /&gt;<br>  &lt;/conditions&gt;<br>  &lt;action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" /&gt;<br> &lt;/rule&gt;</pre>
<p>While we're adding redirects, it's good for search engines to have just one domain to look at, so I can set up a redirect that strips "www" from any requests (which will then feed into the rule above and makes sure to redirect to HTTPS):</p>
<pre> &lt;rule name="Strip www. from URL" stopProcessing="true"&gt;<br>  &lt;match url="^(.*)$" ignoreCase="true" /&gt;<br>  &lt;conditions logicalGrouping="MatchAll"&gt;<br>   &lt;add input="{HTTP_HOST}" pattern="^www\.(.+)$" /&gt;<br>  &lt;/conditions&gt;<br>  &lt;action type="Redirect" url="http://{C:1}/{R:1}" redirectType="Permanent" /&gt;<br> &lt;/rule&gt;</pre>
<p>To further minimize any attacks where bad guys might want to trick you into using insecure HTTP request, you can send up a header with each request called <a href="https://scotthelme.co.uk/hsts-the-missing-link-in-tls/">the HTTP Strict Transport Security (HSTS) header</a>. Enabling HSTS will tell the browser: for the specified amount of time you will not look up any pages on this domain over HTTP any more, always use HTTPS. This is an addition that can be made to the system.webServer/rewrite/outboundRules section:</p>
<pre> &lt;outboundRules&gt;<br>  &lt;rule name="Add Strict-Transport-Security when HTTPS" enabled="true"&gt;<br>  &lt;match serverVariable="RESPONSE_Strict_Transport_Security" pattern=".*" /&gt;<br>  &lt;conditions&gt;<br>   &lt;add input="{HTTPS}" pattern="on" ignoreCase="true" /&gt;<br>   &lt;add input="{HTTP_HOST}" pattern="localhost" negate="true" /&gt;<br>  &lt;/conditions&gt;<br>  &lt;action type="Rewrite" value="<span>max-age=63072000; includeSubDomains; preload</span>" /&gt;<br>  &lt;/rule&gt;<br> &lt;/outboundRules&gt;</pre>
<p>This adds the "Strict-Transport-Security" header that tells browsers: for the next 63072000 seconds (which is two years) the browser should not make any HTTP requests to this domain.</p>
<p><strong>Note:</strong> the rules for HSTS inclusion might change from time to time. Make sure to <a href="https://hstspreload.appspot.com/">read the current requirements</a> before you follow these steps.</p>
<p>However... there's still a tiny sliver of an attack vector here. If you are a <em>Man in the Middle</em> and manage to lure someone to a site that they've never visited before, their very first request will still be the only one ever to go over HTTP. In that single request the Man in the Middle could still possibly do bad things. The only way to eliminate this risk is to never allow HTTP connections to the site, but then everybody needs to know that you can only ever get to the site by prefixing it with "https://". Not very user friendly.</p>
<p>You can, however, ask to be put on a list that is baked into browsers like Chrome, Firefox, Safari, IE11 and Edge. This is called <a href="https://scotthelme.co.uk/hsts-preloading/">HSTS Preloading</a> and takes a few weeks to get set up (it's a manual process). When you do finally make it on this preloaded list, your browser will never request any pages over HTTP but choose HTTPS by default. Part of the manual check that Google will do is to see if HSTS is set up including subdomains and if the preload parameter is there, this is why they're added to the rewrite rule above.</p>
<p><img style="width: 500px; height: 414.42048517520215px;" src="https://cultiv.nl/media/8366/2016-03-25_143859.png?width=500&amp;height=414.42048517520215" alt="" data-id="1701"></p>
<h3>ASafaWeb</h3>
<p>The "Automated Security Analyser for ASP.NET Websites" will test your Umbraco site for known issues with ASP.NET websites. I'm not doing so well on this one and have a few things to fix.</p>
<p><img style="width: 500px; height: 335.30106257378986px;" src="https://cultiv.nl/media/8363/2016-03-25_123807.png?width=500&amp;height=335.30106257378986" alt="" data-id="1698"></p>
<p>AsafaWeb gives me excellent guidance to fix things like Custom Errors and an exposed Stack Trace, just update the web.config to set Custom Errors to "RemoteOnly" and we're good.</p>
<p>As for the orange warnings:</p>
<ul>
<li>Excessive headers: The header "Server: Microsoft-IIS/8.5" gets sent with each response. I have tried disabling this but apparently our UaaS servers forcefully add this header. Nothing I could do about it, this needs to be removed at a server level. There's many other ways to probe sites and find out (by looking at their behavior) that it's running IIS and even which version it runs. So attackers specifically out to target my site are only a few seconds extra delayed in picking the correct attack vectors, I'm not worried about this header.</li>
<li>HTTP only cookies: The "ARRAffinity" cookie is only there for IIS to quickly determine on which of the available web servers my website lives. It's not an attack vector: if it's wrong or doesn't exist, this cookie will just be overwritten with a new one.</li>
<li>Clickjacking: A valid concern, I can deny people framing my site with the simple addition of "X-Frame-Options" to the web.config (more on this later!). <br><strong>Note:</strong> Always make sure you remove a custom header first, if the webserver already has it's own "add" rule, then you can't overwrite it by inserting your own, you need to remove the existing one first. Also note that Umbraco has tried to be helpful and removed the header that tells the world what MVC version you're running by removing "X-Powered-By" in the systemWebserver/httpProtocol/customHeaders section of your web.config.<br>
<pre> &lt;httpProtocol&gt;<br>  &lt;customHeaders&gt;<br>   &lt;!-- Ensure the powered by header is not returned --&gt;<br>   &lt;remove name="X-Powered-By" /&gt;<br>   &lt;remove name="X-Frame-Options" /&gt;<br>   &lt;add name="X-Frame-Options" value="DENY" /&gt;<br>  &lt;/customHeaders&gt;<br> &lt;/httpProtocol&gt;</pre>
</li>
</ul>
<p>There's a few gray boxes there: because my site doesn't have a view state in the HTML, AsafaWeb assumes (correctly) that I'm not using WebForms, so those tests didn't need to run any further. I couldn't figure out how to trigger the "Hash dos patch" test, even after adding a form that does a POST (as described on AsafaWeb) it doesn't test for this problem. Luckily I know that UaaS runs on servers not affected by the <a href="http://technet.microsoft.com/en-us/security/bulletin/ms11-100" target="_blank">MS11-100</a> security vulnerability, but you might want to check with your hosting provider.</p>
<p>Looks better now:</p>
<p><img style="width: 500px; height: 107.18870346598203px;" src="https://cultiv.nl/media/8365/2016-03-25_130445.png?width=500&amp;height=107.18870346598203" alt="" data-id="1700"></p>
<h3>Security-headers.io</h3>
<p>Going even further down into securing our website, there's some "fun" things we can do to make most websites misbehave, <a href="http://www.troyhunt.com/2015/09/introducing-you-to-browser-security.html">like making it do the Harlem Shake</a>.</p>
<p><a href="https://securityheaders.io">Security-headers.io</a> looks to see if you've implemented policies to mitigate these kinds of problems which are mostly XSS (cross site scripting) based. Look at this result.. ouch:</p>
<p><img style="width: 500px; height: 452.8301886792453px;" src="https://cultiv.nl/media/8367/2016-03-25_144806.png?width=500&amp;height=452.8301886792453" alt="" data-id="1702"></p>
<p>We can easily makes this a lot better by following some of the advise here on adding a "X-Xss-Protection" and a "X-Content-Type-Options" header:</p>
<pre> &lt;httpProtocol&gt;<br>  &lt;customHeaders&gt;<br>   &lt;!-- Ensure the powered by header is not returned --&gt;<br>   &lt;remove name="X-Powered-By" /&gt;<br>   &lt;remove name="X-Frame-Options" /&gt;<br>   &lt;add name="X-Frame-Options" value="DENY" /&gt;<br>   &lt;remove name="X-Xss-Protection" /&gt;<br>   &lt;add name="X-Xss-Protection" value="1; mode=block" /&gt;<br>   &lt;remove name="X-Content-Type-Options" /&gt;<br>   &lt;add name="X-Content-Type-Options" value="nosniff" /&gt;<br>  &lt;/customHeaders&gt;<br> &lt;/httpProtocol&gt;</pre>
<p>Better:</p>
<p><img style="width: 500px; height: 213.2486388384755px;" src="https://cultiv.nl/media/8368/2016-03-25_145128.png?width=500&amp;height=213.2486388384755" alt="" data-id="1703"></p>
<p>The <a href="https://scotthelme.co.uk/content-security-policy-an-introduction/">Content Security Policy (CSP)</a> is a lot harder to implement because it requires you to look at all of your site's assets and whitelist them. This is difficult especially if you load video's from YouTube, use CDN hosted javascript libraries, links to external images etc. Which brings us to the following check to run.</p>
<h3>CSP Analyser</h3>
<p>The <a href="https://report-uri.io/home/analyse">CSP analyser over at report-uri.io</a> looks at any policies you've implemented and tells you how good they are. It's impossible to give a good policy for all websites, so I'll just post the one I've struggled with and finally landed on for this site:</p>
<pre> &lt;httpProtocol&gt;<br>  &lt;customHeaders&gt;<br>   &lt;!-- Ensure the powered by header is not returned --&gt;<br>   &lt;remove name="X-Powered-By" /&gt;<br>   &lt;remove name="X-Frame-Options" /&gt;<br>   &lt;add name="X-Frame-Options" value="DENY" /&gt;<br>   &lt;remove name="X-Xss-Protection" /&gt;<br>   &lt;add name="X-Xss-Protection" value="1; mode=block" /&gt;<br>   &lt;remove name="X-Content-Type-Options" /&gt;<br>   &lt;add name="X-Content-Type-Options" value="nosniff" /&gt;<br>   &lt;remove name="Content-Security-Policy" /&gt;<br>   &lt;add name="Content-Security-Policy" value="default-src 'self' https://www.gravatar.com;script-src 'self' https://www.google-analytics.com https://ssl.google-analytics.com;style-src 'self' 'sha256-MZKTI0Eg1N13tshpFaVW65co/LeICXq4hyVx6GWVlK0=' 'sha256-CwE3Bg0VYQOIdNAkbB/Btdkhul49qZuwgNCMPgNY5zw=' 'sha256-LpfmXS+4ZtL2uPRZgkoR29Ghbxcfime/CsD/4w5VujE=' 'sha256-YJO/M9OgDKEBRKGqp4Zd07dzlagbB+qmKgThG52u/Mk=' https://fonts.googleapis.com;img-src 'self' data: https://www.gravatar.com https://www.google-analytics.com;font-src 'self' https://fonts.gstatic.com https://fonts.googleapis.com;" /&gt;<br>  &lt;/customHeaders&gt;<br> &lt;/httpProtocol&gt;</pre>
<p>I am using Gravatar images, Google Analytics and the Google Fonts API. The sha256 references are there to fix <a href="https://github.com/Modernizr/Modernizr/pull/1263">some things that Modernizr.js wants to execute</a>, which wouldn't otherwise be allowed, Chrome dev tools will tell you exactly what to add if this is a problem for you:</p>
<p><img style="width: 500px; height: 302.937576499388px;" src="https://cultiv.nl/media/8369/2016-03-25_150753.png?width=500&amp;height=302.937576499388" alt="" data-id="1704"></p>
<p>To make it a bit easier for you to manage, <a href="https://report-uri.io/register/">report-uri.io allows you to set up a free</a><a href="https://report-uri.io/register/"> account</a>. Using that, all CSP violations will be logged for you so you can have a look at updating your whitelist accordingly.</p>
<p>After setting up a CSP, securityheaders.io now reports a respectable "A" grade.</p>
<p><img style="width: 500px; height: 159.5744680851064px;" src="https://cultiv.nl/media/8370/2016-03-25_152221.png?width=500&amp;height=159.5744680851064" alt="" data-id="1705"></p>
<p>I've looked into <a href="https://scotthelme.co.uk/hpkp-http-public-key-pinning/">Public Key Pinning (HPKP)</a> but the process seems too onerous for little gain for now. The problem with HPKP is currently that I don't understand how backup CSRs are supposed to work and what exactly I need to do when my current certificate expires. I have done some experiments and they worked but I need to do further testing to see what it will take to switch to a new certificate.</p>
<p>In case you are wondering (and are brave), the HPKP header can be configured like so in system.webServer/httpProtocol/customHeaders:</p>
<pre> &lt;remove name="Public-Key-Pins" /&gt;<br> &lt;add name="Public-Key-Pins" value="max-age=31536000; pin-sha256=&amp;quot;h2EVK2+bga6XAxu7ImUQM0PJsgZd2/a2VtlcSmV87s4=&amp;quot;; pin-sha256=&amp;quot;9ilXj1leytbsCvXVIFJ1uzjmej2bzs05qzRzmfFzXKs=&amp;quot;; pin-sha256=&amp;quot;nupZBiNmjIMxIyEll+OBYjvMORUEyYTTr7K5bE2z7L0=&amp;quot;;" /&gt;</pre>
<p>Note that the double quotes need to be escaped because the web.config file is an XML file, so replace " with &amp;quot; everywhere in the value of this header.</p>
<h2>Back to Umbraco</h2>
<p>Now that we've made our frontend all nice and safe, let's go back into the backoffice of Umbraco.</p>
<p><img style="width: 500px; height: 364.5287958115183px;" src="https://cultiv.nl/media/8371/2016-03-25_153006.png?width=500&amp;height=364.5287958115183" alt="" data-id="1706"></p>
<p>Whoops, we broke it!</p>
<p>There's a few things going on in the backoffice that we need to allow now that we've disallowed a lot of them on the frontend. Umbraco still uses iframes for some pages in the backoffice so we'll need to allow those. The Content Security Policy is also blocking a lot of asset loading because they're set pretty strict on the frontend.</p>
<p>Luckily we don't have to change our frontend setup, we can just change the backoffice requirements a little bit. All the way at the bottom of our web.config we already have a &lt;location path="umbraco"&gt; section which tells IIS: for this location (the umbraco path) we want to apply different rules then for the rest of the site. We can amend this section with a custom CSP and allow frames from the same origin (so only frames with a location that lives somewhere in our site).</p>
<p>We're already disabling urlCompression for the backoffice as that can conflict with our backoffice javascripts, so let's add our updated headers there:</p>
<pre> &lt;location path="umbraco"&gt;<br>  &lt;system.webServer&gt;<br>   &lt;urlCompression doStaticCompression="false" doDynamicCompression="false" dynamicCompressionBeforeCache="false" /&gt;<br>   &lt;httpProtocol&gt;<br>    &lt;customHeaders&gt;<br>     &lt;remove name="X-Frame-Options" /&gt;<br>     &lt;add name="X-Frame-Options" value="SAMEORIGIN" /&gt;<br>     &lt;remove name="Content-Security-Policy" /&gt;<br>     &lt;add name="Content-Security-Policy" value="default-src 'self' www.gravatar.com player.vimeo.com *.vimeocdn.com packages.umbraco.org our.umbraco.org;script-src 'self' 'unsafe-inline' 'unsafe-eval';style-src 'self' 'unsafe-inline';img-src 'self' data: www.gravatar.com umbraco.tv;font-src 'self';" /&gt;<br>    &lt;/customHeaders&gt;<br>   &lt;/httpProtocol&gt; <br>  &lt;/system.webServer&gt;<br> &lt;/location&gt;</pre>
<p>Much better, our backoffice is back without errors.</p>
<p><img style="width: 500px; height: 419.89987484355447px;" src="https://cultiv.nl/media/8372/2016-03-25_154009.png?width=500&amp;height=419.89987484355447" alt="" data-id="1707"></p>
<p>One interesting thing I found when implementing CSP rules is that I was not allowed to have inline CSS in my site, this is a good thing, I don't want inline CSS, I want everything to be nicely tucked away in a CSS file.</p>
<p>One problem though: the rich text editor. When you insert an image in the RTE, Umbraco automatically adds an inline style for you with the dimensions of the image and there seems to be no way to prevent it from doing so. </p>
<p><img style="width: 500px; height: 384.7477064220183px;" src="https://cultiv.nl/media/8373/2016-03-25_160051.png?width=500&amp;height=384.7477064220183" alt="" data-id="1708"></p>
<p>I've created a simple extension method that goes through your html and strips out those inline styles. This StringExtensions.cs can be dropped into your App_Code folder:</p>
<pre>using System.Web;<br>using HtmlAgilityPack;<br><br>namespace Cultiv.StringExtensions<br>{<br>  public static class RteStyles<br>  {<br>    public static IHtmlString RemoveInlineImageStyles(this string text) <br>    {<br>      var htmlString = new HtmlString(text);<br>      return htmlString.RemoveInlineImageStyles();<br>    }<br> <br>    public static IHtmlString RemoveInlineImageStyles(this IHtmlString htmlString)<br>    {<br>      var htmlDocument = new HtmlDocument();<br>      htmlDocument.LoadHtml(htmlString.ToString());<br>      if(htmlDocument == null || htmlDocument.DocumentNode == null || htmlDocument.DocumentNode.SelectNodes("//img[@style]") == null) <br>      {<br>        return htmlString;<br>      }<br>      else<br>      {<br>        foreach (var node in htmlDocument.DocumentNode.SelectNodes("//img[@style]"))<br>        {<br>          var attribute = node.Attributes["style"];<br>          node.Attributes.Remove("style");<br>        }<br>      }<br>      return new HtmlString(htmlDocument.DocumentNode.OuterHtml);<br>    }<br>  }<br>}</pre>
<p>I use it as follows in my templates:</p>
<pre>@(Model.Content.GetPropertyValue&lt;string&gt;("bodyText").RemoveInlineImageStyles())</pre>
<h2>Conclusion</h2>
<p>Security is hard. :-)</p>
<p>Luckily there's plenty of tools that help ease the pain. We are always looking into updating Umbraco where possible to take away the pain by setting up sensible defaults. We're also working on making things easier to set up on Umbraco as a Service where we can rely more on automation.</p>
<p>There's a few security related sites I should point to that are excellent in helping you understand security and keeping you safe:</p>
<ul>
<li>Follow <a href="http://www.troyhunt.com/">Troy Hunt's blog</a> and <a href="https://twitter.com/troyhunt">Twitter account</a> (or whatever social media you like, there's plenty of icons on his site)
<ul>
<li>If you have a PluralSight account, <a href="http://app.pluralsight.com/author/troy-hunt">his security courses are always great</a> as well </li>
</ul>
</li>
<li>Follow <a href="https://scotthelme.co.uk/">Scott Helme's blog</a> and <a href="https://twitter.com/Scott_Helme/">Twitter account</a></li>
<li>I enjoy <a href="https://twit.tv/shows/security-now">the Security Now podcast</a> for regular in depth discussions of how security works (and most notably: where it fails, of course) and recommend playing it at 1.5 speed</li>
</ul>
<p>Finally: there's a lot more you can do to protect your site, but this is a mammoth post already so I'll end this here in hopes that I get more time in the future to cover related topics.</p>
<p> </p>]]>
                </content:encoded>
            </item>
            <item>
                <title>How to diagnose Umbraco upgrade problems</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/how-to-diagnose-umbraco-upgrade-problems/</link>
                <pubDate>Sat, 27 Feb 2016 12:49:15 GMT</pubDate>
                <guid>https://cultiv.nl/blog/how-to-diagnose-umbraco-upgrade-problems/</guid>
                <description>
                    <![CDATA[<p>Upgrading Umbraco.. one of my favorite thing to do! Not yours? Having problems? Okay.. let's see what we can do about that.</p>
<p>First of all: we test upgrading for every Umbraco version we release. We upgrade the solution we use for masterclasses, we upgrade <a href="https://our.umbraco.org">Our Umbraco</a> and when there's big changes we upgrade a bunch of other random sites too. So when it doesn't work for you, it's most likely that something went wrong on your computer, not in our upgrader. I'm not blaming the "victim" here, but just want to make you aware that we do all we can to make your upgrades succeed the first time. We miss stuff sometimes though, and that sucks, in which case we either try to correct that quickly or at least document it. </p>
<p>We also document how to upgrade your site as comprehensively as possible, so make sure to read the documentation, loads of hints and tips that we keep up to date:</p>
<ul>
<li><a href="https://our.umbraco.org/documentation/Getting-Started/Setup/Upgrading/general">The general upgrade guide</a></li>
<li><a href="https://our.umbraco.org/documentation/Getting-Started/Setup/Upgrading/version-specific">The version specific upgrade guide</a></li>
</ul>
<p>Needless to say: you have your code checked into source control (or at the very least backed up before you upgrade) and you've made a full database backup before upgrading your site, right?</p>
<p><strong>Troubleshooting</strong></p>
<p>With that out of the way: shit happens! So let's try to figure it out.<br>I like to think of the Umbraco ZIP downloads as the "known good" state; when you have "problem x" after upgrading and installing a clean Umbraco install does not have "problem x" then something most likely went wrong with your upgrade.</p>
<p>Most people these days use NuGet for installing and upgrading Umbraco, that's also where most people have problems as it LOOKS like everything is done automatically for you, but sometimes it hasn't worked. NuGet can have a temperament where it "forgets" to do config transforms, runs into problems while doing the upgrade or "forgets" to copy certain files.</p>
<p>Time to debug! Let's start with the 3 C's: <em>configs</em>, <em>cache</em> and <em>cookies</em>.</p>
<p><strong>Configs</strong></p>
<p>Check that your config files in the ~/Config folder have been updated, and especially check if both your web.config files (the one in the root of your site and the on in the ~/Views folder) have been updated. How? Aha! Here is the <strong>best</strong> tip I will give you in this blog post: download a copy of <a href="http://www.scootersoftware.com/">BeyondCompare</a> and <a data-id="1681" href="https://cultiv.nl/media/8354/bcpreferences.bcpkg" title="BCPreferences.bcpkg">import these settings</a>. Finally, make sure to click the "Ignore unimportant differences" button, which hides unimportant whitespace differences.</p>
<p><img style="width: 500px; height: 320.37914691943126px;" src="https://cultiv.nl/media/8355/2016-02-27_143033.png?width=500&amp;height=320.37914691943126" alt="" data-id="1682"></p>
<p>Right, with a beautiful BeyondCompare install in place, <a href="https://our.umbraco.org/contribute/releases/">download the zip file corresponding to the Umbraco version</a> you're trying to upgrade to. Right click the zip file and choose <em>"Select left folder for compare"</em>, then find the folder where your Umbraco install lives, right click it and choose <em>"Compare to UmbracoCms.x.y.z.zip"</em>. You'll get a nice overview of folders and some will disappear as they're the same on both sides, leaving you with just the differences.</p>
<p>The first thing I usually check is the root web.config to make sure that everything that might be new in the Umbraco default web.config file is in the web.config file in my site. A special section to pay attention to is the <strong>runtime/assemblyBinding</strong> one that really needs the <strong>bindingRedirect</strong> versions to be correct.</p>
<p>After you've updated config files: try again, your site probably works just fine now.</p>
<p><em>Extra tip:</em> while you're comparing it's also a great moment to check that all the required files are in your bin folder, we ship with what's needed in the zip file so make sure that all the files on the left side are also on the right side and that the versions are the same. Again, BeyondCompare only shows you the differences between the two folders so it should be easy to spot if anything is amiss.</p>
<p><em>Note: </em>Yes, I know this is possible with <a href="http://winmerge.org/">WinMerge</a> and other compare tools as well, but BeyondCompare is so much better than all of the others.</p>
<p><strong>Cache</strong></p>
<p>No? Okay then, try clearing your browser cache. Umbraco uses a lot javascript/angular/html that changes for most releases. The first thing to check: ~/Config/ClientDependency.config. Change the version number in that file (just make it 1 higher or lower) and try again. This should clear client side cache for most browsers.</p>
<p>However.. Chrome in particular is super aggressive in caching so it might not make a difference. So, for another hot tip in this post: if you use Chrome, hit the F12 button and the reload button next to the address bar is a little bit magical now. Try right-clicking on it...</p>
<p><img style="width: 355px; height: 116px;" src="https://cultiv.nl/media/8356/2016-02-27_135532.png?width=355&amp;height=116" alt="" data-id="1683"></p>
<p>You now have options! The best one of which is: <em>Empty Cache and Hard Reload</em>. It does what it says on the tin and requests all assets completely freshly and should load whatever is updated in Umbraco.</p>
<p><strong>Cookies</strong></p>
<p>We recently had a problem where an old cookie would throw a spanner in the works. Again, the developer tools in your browser can come to the rescue, I have the most experience with Chrome so again, hit the F12 button and go to the resources tab to find and delete all cookies.</p>
<p><img style="width: 500px; height: 216.53543307086613px;" src="https://cultiv.nl/media/8357/2016-02-27_144655.png?width=500&amp;height=216.53543307086613" alt="" data-id="1684"></p>
<p><strong>Other problems</strong></p>
<p>Check your log files, in ~/App_Data/Logs/ - whenever there's any kind of error that we can log, it will be in here. Look for things that look suspicious in the last few minutes that you were working on your upgrade and then do the simplest thing possible: copy an error and paste it into Google. <strong>You won't believe what happens next!</strong> (sorry.. I'm so sorry..).</p>
<p>Over the years Umbraco has had some let's say "interesting" database upgrades. Since v6 we have made this much more consistent and when the Umbraco upgrade installer runs we try to anticipate all the exotic database schema variations we had in the past and make everything consistent again. If you see database errors during an upgrade, it's likely that you're not the first person to see it, google it and see if there's manual workarounds. We try to pick up all of these errors and fix them in the next version so they don't pop up any more.</p>
<p>We sometimes break things, when it's on purpose we list them as being breaking changes on the release page of the version you're trying to upgrade to, if there's multiple versions between your current version and the version you're upgrading to, you might have to read up on all of the release pages to see if anything broke due to a change we made. So say you're upgrading from 7.3.6 to 7.4.1, make sure to read the release notes of 7.3.7, 7.3.8, 7.4.0.</p>
<p><strong>But why?!</strong></p>
<p>Yes, we do hear you cry "why can't it just work?!". Well, mostly: people do wildly different things with Umbraco. We learn every day and when we learn about something new and unexpected, we update the upgrade installer. This is an ongoing process that will never be perfect but it so much better than it was a few years ago. The NuGet experience these days is almost seamless and I encourage everyone with a new project to start out with a NuGet install and stick with it (even though it has grumpy days sometimes). It's well worth investing time in learning how NuGet works and what it does.</p>
<p><strong>Automatic upgrades</strong></p>
<p>Oh, and one more thing, on <a href="http://umbraco.com/cloud">Umbraco as a Service</a>, you get automatic upgrades. So you don't have to worry about any of this. You just wake up one day and see a message in the portal and continue making great sites for your clients.</p>
<p><img style="width: 500px; height: 142.17443249701316px;" src="https://cultiv.nl/media/8359/2016-02-27_151239.png?width=500&amp;height=142.17443249701316" alt="" data-id="1685"></p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Upgrading Umbraco.. one of my favorite thing to do! Not yours? Having problems? Okay.. let's see what we can do about that.</p>
<p>First of all: we test upgrading for every Umbraco version we release. We upgrade the solution we use for masterclasses, we upgrade <a href="https://our.umbraco.org">Our Umbraco</a> and when there's big changes we upgrade a bunch of other random sites too. So when it doesn't work for you, it's most likely that something went wrong on your computer, not in our upgrader. I'm not blaming the "victim" here, but just want to make you aware that we do all we can to make your upgrades succeed the first time. We miss stuff sometimes though, and that sucks, in which case we either try to correct that quickly or at least document it. </p>
<p>We also document how to upgrade your site as comprehensively as possible, so make sure to read the documentation, loads of hints and tips that we keep up to date:</p>
<ul>
<li><a href="https://our.umbraco.org/documentation/Getting-Started/Setup/Upgrading/general">The general upgrade guide</a></li>
<li><a href="https://our.umbraco.org/documentation/Getting-Started/Setup/Upgrading/version-specific">The version specific upgrade guide</a></li>
</ul>
<p>Needless to say: you have your code checked into source control (or at the very least backed up before you upgrade) and you've made a full database backup before upgrading your site, right?</p>
<p><strong>Troubleshooting</strong></p>
<p>With that out of the way: shit happens! So let's try to figure it out.<br>I like to think of the Umbraco ZIP downloads as the "known good" state; when you have "problem x" after upgrading and installing a clean Umbraco install does not have "problem x" then something most likely went wrong with your upgrade.</p>
<p>Most people these days use NuGet for installing and upgrading Umbraco, that's also where most people have problems as it LOOKS like everything is done automatically for you, but sometimes it hasn't worked. NuGet can have a temperament where it "forgets" to do config transforms, runs into problems while doing the upgrade or "forgets" to copy certain files.</p>
<p>Time to debug! Let's start with the 3 C's: <em>configs</em>, <em>cache</em> and <em>cookies</em>.</p>
<p><strong>Configs</strong></p>
<p>Check that your config files in the ~/Config folder have been updated, and especially check if both your web.config files (the one in the root of your site and the on in the ~/Views folder) have been updated. How? Aha! Here is the <strong>best</strong> tip I will give you in this blog post: download a copy of <a href="http://www.scootersoftware.com/">BeyondCompare</a> and <a data-id="1681" href="https://cultiv.nl/media/8354/bcpreferences.bcpkg" title="BCPreferences.bcpkg">import these settings</a>. Finally, make sure to click the "Ignore unimportant differences" button, which hides unimportant whitespace differences.</p>
<p><img style="width: 500px; height: 320.37914691943126px;" src="https://cultiv.nl/media/8355/2016-02-27_143033.png?width=500&amp;height=320.37914691943126" alt="" data-id="1682"></p>
<p>Right, with a beautiful BeyondCompare install in place, <a href="https://our.umbraco.org/contribute/releases/">download the zip file corresponding to the Umbraco version</a> you're trying to upgrade to. Right click the zip file and choose <em>"Select left folder for compare"</em>, then find the folder where your Umbraco install lives, right click it and choose <em>"Compare to UmbracoCms.x.y.z.zip"</em>. You'll get a nice overview of folders and some will disappear as they're the same on both sides, leaving you with just the differences.</p>
<p>The first thing I usually check is the root web.config to make sure that everything that might be new in the Umbraco default web.config file is in the web.config file in my site. A special section to pay attention to is the <strong>runtime/assemblyBinding</strong> one that really needs the <strong>bindingRedirect</strong> versions to be correct.</p>
<p>After you've updated config files: try again, your site probably works just fine now.</p>
<p><em>Extra tip:</em> while you're comparing it's also a great moment to check that all the required files are in your bin folder, we ship with what's needed in the zip file so make sure that all the files on the left side are also on the right side and that the versions are the same. Again, BeyondCompare only shows you the differences between the two folders so it should be easy to spot if anything is amiss.</p>
<p><em>Note: </em>Yes, I know this is possible with <a href="http://winmerge.org/">WinMerge</a> and other compare tools as well, but BeyondCompare is so much better than all of the others.</p>
<p><strong>Cache</strong></p>
<p>No? Okay then, try clearing your browser cache. Umbraco uses a lot javascript/angular/html that changes for most releases. The first thing to check: ~/Config/ClientDependency.config. Change the version number in that file (just make it 1 higher or lower) and try again. This should clear client side cache for most browsers.</p>
<p>However.. Chrome in particular is super aggressive in caching so it might not make a difference. So, for another hot tip in this post: if you use Chrome, hit the F12 button and the reload button next to the address bar is a little bit magical now. Try right-clicking on it...</p>
<p><img style="width: 355px; height: 116px;" src="https://cultiv.nl/media/8356/2016-02-27_135532.png?width=355&amp;height=116" alt="" data-id="1683"></p>
<p>You now have options! The best one of which is: <em>Empty Cache and Hard Reload</em>. It does what it says on the tin and requests all assets completely freshly and should load whatever is updated in Umbraco.</p>
<p><strong>Cookies</strong></p>
<p>We recently had a problem where an old cookie would throw a spanner in the works. Again, the developer tools in your browser can come to the rescue, I have the most experience with Chrome so again, hit the F12 button and go to the resources tab to find and delete all cookies.</p>
<p><img style="width: 500px; height: 216.53543307086613px;" src="https://cultiv.nl/media/8357/2016-02-27_144655.png?width=500&amp;height=216.53543307086613" alt="" data-id="1684"></p>
<p><strong>Other problems</strong></p>
<p>Check your log files, in ~/App_Data/Logs/ - whenever there's any kind of error that we can log, it will be in here. Look for things that look suspicious in the last few minutes that you were working on your upgrade and then do the simplest thing possible: copy an error and paste it into Google. <strong>You won't believe what happens next!</strong> (sorry.. I'm so sorry..).</p>
<p>Over the years Umbraco has had some let's say "interesting" database upgrades. Since v6 we have made this much more consistent and when the Umbraco upgrade installer runs we try to anticipate all the exotic database schema variations we had in the past and make everything consistent again. If you see database errors during an upgrade, it's likely that you're not the first person to see it, google it and see if there's manual workarounds. We try to pick up all of these errors and fix them in the next version so they don't pop up any more.</p>
<p>We sometimes break things, when it's on purpose we list them as being breaking changes on the release page of the version you're trying to upgrade to, if there's multiple versions between your current version and the version you're upgrading to, you might have to read up on all of the release pages to see if anything broke due to a change we made. So say you're upgrading from 7.3.6 to 7.4.1, make sure to read the release notes of 7.3.7, 7.3.8, 7.4.0.</p>
<p><strong>But why?!</strong></p>
<p>Yes, we do hear you cry "why can't it just work?!". Well, mostly: people do wildly different things with Umbraco. We learn every day and when we learn about something new and unexpected, we update the upgrade installer. This is an ongoing process that will never be perfect but it so much better than it was a few years ago. The NuGet experience these days is almost seamless and I encourage everyone with a new project to start out with a NuGet install and stick with it (even though it has grumpy days sometimes). It's well worth investing time in learning how NuGet works and what it does.</p>
<p><strong>Automatic upgrades</strong></p>
<p>Oh, and one more thing, on <a href="http://umbraco.com/cloud">Umbraco as a Service</a>, you get automatic upgrades. So you don't have to worry about any of this. You just wake up one day and see a message in the portal and continue making great sites for your clients.</p>
<p><img style="width: 500px; height: 142.17443249701316px;" src="https://cultiv.nl/media/8359/2016-02-27_151239.png?width=500&amp;height=142.17443249701316" alt="" data-id="1685"></p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Let&#39;s Encrypt, on Windows</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/lets-encrypt-on-windows/</link>
                <pubDate>Sun, 06 Dec 2015 09:51:56 GMT</pubDate>
                <guid>https://cultiv.nl/blog/lets-encrypt-on-windows/</guid>
                <description>
                    <![CDATA[<p>I've been learning a lot about security and https in the last year or so and acquiring a certificate has always been a bit of a drag. Sure, <a href="https://dnsimple.com/">DNSimple</a> has made it pretty easy and affordable but it's still $20 a year for something that is 100% automated, all they have to do is keep their systems working and reap the benefits.</p>
<p> </p>
<p><strong>Update</strong>: this is getting much easier already, <a data-id="1846" href="https://cultiv.nl/blog/lets-encrypt-on-windows-revisited/" title="Let's Encrypt on Windows revisited">check out the follow up post</a> to this one.</p>
<p> </p>
<p>So I was very excited to learn about a year ago about the formation of <a href="https://letsencrypt.org/"><strong>Let's Encrypt</strong></a>. As they <a href="https://letsencrypt.org/about/">describe</a> it: "<span>Anyone who owns a domain name can use Let’s Encrypt to obtain a trusted certificate at zero cost.". </span></p>
<p><span>Awesome! They have some good sponsors and I'm donor for <a href="https://supporters.eff.org/donate">the Electronic Fronteer Foundation</a>, which started this initiative so in a way, I'm still paying for my certificates, sort of. ;-)</span></p>
<p>I was super excited this week to see that Let's Encrypt was in public beta now and wanted to play with it! But.. of course all of the official tooling focuses on Linux environments and it's been a while for me since I used that. So, I found a cool little project on GitHub called <a href="https://github.com/ebekker/ACMESharp">ACMESharp</a>, implementing the protocol and APIs used by Let's Encrypt using PowerShell.</p>
<p>It took me a while to wrap my head around it but it all makes sense now after playing with it for a while, there's really only 3 steps:</p>
<ol>
<li>You have to agree to the terms of service</li>
<li>You have to prove that you own the domain that you want a certificate for</li>
<li>You request the certificate</li>
</ol>
<p>The <a href="https://github.com/ebekker/ACMESharp/wiki/Example-Usage">documentation for ACMESharp</a> gave me some clues as to how this works but there was still a few "gotcha" moments there. I'll lead you through the PowerShell script that I came up with:</p>
<pre>Import-Module -Name D:\Temp\ACME-posh\ACMEPowerShell.psd1<br />$domain = "cork.nl"<br />$certificiatePassword = "abcd1234"<br />$email = "letsencrypt@cork.nl"<br />$vault = "D:\Vault\{0}\{1}" -f $domain, [guid]::NewGuid()<br />mkdir $vault<br />cd $vault</pre>
<p>Some setup cruft - first of all, you download the ACMESharp <a href="https://github.com/ebekker/ACMESharp/releases">release</a> that's available and unzip it somewhere and import the module you find in there. I make a new folder for each attempt at running this script by generating a new GUID each time.</p>
<p>Next up: pointing to the public beta server that will give you a real, trusted certificate. At first the URL I had here was still pointing at the staging server which gives you cerificates issued by "happy hacker fake CA". Needless to say: I can't use those in production.</p>
<pre>Initialize-ACMEVault -BaseURI https://acme-v01.api.letsencrypt.org/<br />New-ACMERegistration -Contacts mailto:$email<br />Update-ACMERegistration -AcceptTOS</pre>
<p>The terms of service are accepted here and I give them my email address, this was a little confusing as I was waiting for an email to come in to click the "Accept TOS" link but it didn't come. Good, because this is now fully automated, I can just tell them in PowerShell that I accept the terms of service, which I obviously studied closely (not!).</p>
<p>Okay, now the fun part starts: verifying that you own the domain. You ask Let's encrypt to give you a secret randomly generated blob of text that you, as the site owner can put on your website.</p>
<pre>New-ACMEIdentifier -Dns $domain -Alias dns1<br />New-ACMEProviderConfig -WebServerProvider Manual -Alias manualHttpProvider -FilePath $vault\answer.txt<br />Get-ACMEIdentifier -Ref dns1<br />$completedChallenge = Complete-ACMEChallenge -Ref dns1 -Challenge http-01 -ProviderConfig manualHttpProvider</pre>
<p>Note: the FilePath variable in New-ACMEProviderConfig doesn't exist in the 0.7.1 release. I created a pull request to add that to ACMESharp and it was accepted an hour later (yay!). If you use this right now, you'll get an instance of Notepad popping up asking you to complete the FilePath in the bit of JSON that gets put into Notepad. I like automation so I asked if it could just be a variable. </p>
<p>Now, the Complete-ACMEChallenge command returns all the information you need to complete the challenge, I didn't read this properly at first so I wasn't sure what to do. I did it wrong and then the challenge status was set to 'invalid'. Even after correcting my mistake and following the instructions, it was still 'invalid'. "Damn it! Now I'll never be able to get my certificate..". Or so I thought. After Googling for a bit I found out that once a challenge was marked as invalid once, it would never become valid (there's good security reasons behind this, preventing replay attacks). So the trick is to ask for a new challenge, easy!</p>
<p>I added some output to my PowerShell script to remind me exactly what to do:</p>
<pre>$challengeAnswer = ($completedChallenge.Challenges | Where-Object { $_.Type -eq "http-01" }).ChallengeAnswer<br />$key = $challengeAnswer.Key<br />Write-Host ""<br />Write-Host "Create folder structure on $domain like so:"<br />Write-Host "$domain/$key"<br />Write-Host "Put an index.html file in that location that contains:"<br />Write-Host $challengeAnswer.Value</pre>
<p>Which outputs something like this:</p>
<pre>Create folder structure on cork.nl like so:<br />cork.nl/.well-known/acme-challenge/V6CPYDViDCk6X3YWC9wH61kKW2CHtQ-SLACnIcBNFPY<br />Put an index.html file in that location that contains:<br />V6CPYDViDCk6X3YWC9wH61kKW2CHtQ-SLACnIcBNFPY.8uMzTUtlJpLEsyNHnTmLutOPZyFv4VUCFwaqram0gRo</pre>
<p>I can do that! So what needs to happen is when the Let's Encrypt server goes to the URL <em>http://cork.nl/.well-known/acme-challenge/V6CPYDViDCk6X3YWC9wH61kKW2CHtQ-SLACnIcBNFPY</em> the body of the response should contain the secret key: <em>V6CPYDViDCk6X3YWC9wH61kKW2CHtQ-SLACnIcBNFPY.8uMzTUtlJpLEsyNHnTmLutOPZyFv4VUCFwaqram0gRo</em></p>
<p>In this case I do this by placing an index.html in the created folder as I know that IIS will serve that up by default, your server might be configured differently so make sure that it outputs the secret key somehow (and only the secret key, nothing else). </p>
<p>Right! Now we can tell Let's Encrypt: I'm ready, please verify:</p>
<pre>$challenge = Submit-ACMEChallenge -Ref dns1 -Challenge http-01<br />While ($challenge.Status -eq "pending") {<br />  Start-Sleep -m 500 # wait half a second before trying<br />  Write-Host "Status is still 'pending', waiting for it to change..."<br />  $challenge = Update-ACMEIdentifier -Ref dns1<br />}</pre>
<p>Here the challenge is submitted and it might take a second for the status to change from "pending" to "valid" so I ask for an update every half second before continuing.</p>
<p>When the status is "valid" we're golden, go get that cert now!</p>
<pre>New-ACMECertificate -Identifier dns1 -Alias cert1 -Generate<br />$certificateInfo = Submit-ACMECertificate -Ref cert1<br /><br />While([string]::IsNullOrEmpty($certificateInfo.IssuerSerialNumber)) {<br /> Start-Sleep -m 500 # wait half a second before trying<br /> Write-Host "IssuerSerialNumber is not set yet, waiting for it to be populated..."<br /> $certificateInfo = Update-ACMECertificate -Ref cert1<br />}<br /><br />Get-ACMECertificate -Ref cert1 -ExportPkcs12 cert1-all.pfx -CertificatePassword $certificiatePassword<br /><br />Write-Host "All done, there's a cert1-all.pfx file in $vault with password $certificiatePassword for you to use now"</pre>
<p>We're asking Let's Encrypt to generate the certificate and then we do another few pings for the IssuerSerialNumber to update, that's when the certificate has been completely generated. Finally we do a Get-ACMECertificate to receive it and it will be stored in the $vault folder. Note: I'm adding a password to this certificate but this functionality is not yet available in the 0.7.1 release of ACMESharp. Again, this was a specific need that I had for which I sent a pull request which was promptly accepted. </p>
<p>If all this sounds like a lot of work: it is not! </p>
<p>Now that you understand what's going on, this process is repeatable. Which is very necessary because <a href="https://letsencrypt.org/2015/11/09/why-90-days.html">by default these certificates expire every 90 days</a> and will expire even more quickly in the future. This is being done to promote security: a compromised certificate can now only be abused for a maximum of 90 days. It's also being done to promote automation: I built a PowerShell script so I can automate this, they achieved their goal!</p>
<p>The <a href="https://gist.github.com/nul800sebastiaan/31b000874ffa69f4c0af">full PS script is available in a gist</a> for you to copy and use.</p>
<p>Go forth and secure your sites!</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>I've been learning a lot about security and https in the last year or so and acquiring a certificate has always been a bit of a drag. Sure, <a href="https://dnsimple.com/">DNSimple</a> has made it pretty easy and affordable but it's still $20 a year for something that is 100% automated, all they have to do is keep their systems working and reap the benefits.</p>
<p> </p>
<p><strong>Update</strong>: this is getting much easier already, <a data-id="1846" href="https://cultiv.nl/blog/lets-encrypt-on-windows-revisited/" title="Let's Encrypt on Windows revisited">check out the follow up post</a> to this one.</p>
<p> </p>
<p>So I was very excited to learn about a year ago about the formation of <a href="https://letsencrypt.org/"><strong>Let's Encrypt</strong></a>. As they <a href="https://letsencrypt.org/about/">describe</a> it: "<span>Anyone who owns a domain name can use Let’s Encrypt to obtain a trusted certificate at zero cost.". </span></p>
<p><span>Awesome! They have some good sponsors and I'm donor for <a href="https://supporters.eff.org/donate">the Electronic Fronteer Foundation</a>, which started this initiative so in a way, I'm still paying for my certificates, sort of. ;-)</span></p>
<p>I was super excited this week to see that Let's Encrypt was in public beta now and wanted to play with it! But.. of course all of the official tooling focuses on Linux environments and it's been a while for me since I used that. So, I found a cool little project on GitHub called <a href="https://github.com/ebekker/ACMESharp">ACMESharp</a>, implementing the protocol and APIs used by Let's Encrypt using PowerShell.</p>
<p>It took me a while to wrap my head around it but it all makes sense now after playing with it for a while, there's really only 3 steps:</p>
<ol>
<li>You have to agree to the terms of service</li>
<li>You have to prove that you own the domain that you want a certificate for</li>
<li>You request the certificate</li>
</ol>
<p>The <a href="https://github.com/ebekker/ACMESharp/wiki/Example-Usage">documentation for ACMESharp</a> gave me some clues as to how this works but there was still a few "gotcha" moments there. I'll lead you through the PowerShell script that I came up with:</p>
<pre>Import-Module -Name D:\Temp\ACME-posh\ACMEPowerShell.psd1<br />$domain = "cork.nl"<br />$certificiatePassword = "abcd1234"<br />$email = "letsencrypt@cork.nl"<br />$vault = "D:\Vault\{0}\{1}" -f $domain, [guid]::NewGuid()<br />mkdir $vault<br />cd $vault</pre>
<p>Some setup cruft - first of all, you download the ACMESharp <a href="https://github.com/ebekker/ACMESharp/releases">release</a> that's available and unzip it somewhere and import the module you find in there. I make a new folder for each attempt at running this script by generating a new GUID each time.</p>
<p>Next up: pointing to the public beta server that will give you a real, trusted certificate. At first the URL I had here was still pointing at the staging server which gives you cerificates issued by "happy hacker fake CA". Needless to say: I can't use those in production.</p>
<pre>Initialize-ACMEVault -BaseURI https://acme-v01.api.letsencrypt.org/<br />New-ACMERegistration -Contacts mailto:$email<br />Update-ACMERegistration -AcceptTOS</pre>
<p>The terms of service are accepted here and I give them my email address, this was a little confusing as I was waiting for an email to come in to click the "Accept TOS" link but it didn't come. Good, because this is now fully automated, I can just tell them in PowerShell that I accept the terms of service, which I obviously studied closely (not!).</p>
<p>Okay, now the fun part starts: verifying that you own the domain. You ask Let's encrypt to give you a secret randomly generated blob of text that you, as the site owner can put on your website.</p>
<pre>New-ACMEIdentifier -Dns $domain -Alias dns1<br />New-ACMEProviderConfig -WebServerProvider Manual -Alias manualHttpProvider -FilePath $vault\answer.txt<br />Get-ACMEIdentifier -Ref dns1<br />$completedChallenge = Complete-ACMEChallenge -Ref dns1 -Challenge http-01 -ProviderConfig manualHttpProvider</pre>
<p>Note: the FilePath variable in New-ACMEProviderConfig doesn't exist in the 0.7.1 release. I created a pull request to add that to ACMESharp and it was accepted an hour later (yay!). If you use this right now, you'll get an instance of Notepad popping up asking you to complete the FilePath in the bit of JSON that gets put into Notepad. I like automation so I asked if it could just be a variable. </p>
<p>Now, the Complete-ACMEChallenge command returns all the information you need to complete the challenge, I didn't read this properly at first so I wasn't sure what to do. I did it wrong and then the challenge status was set to 'invalid'. Even after correcting my mistake and following the instructions, it was still 'invalid'. "Damn it! Now I'll never be able to get my certificate..". Or so I thought. After Googling for a bit I found out that once a challenge was marked as invalid once, it would never become valid (there's good security reasons behind this, preventing replay attacks). So the trick is to ask for a new challenge, easy!</p>
<p>I added some output to my PowerShell script to remind me exactly what to do:</p>
<pre>$challengeAnswer = ($completedChallenge.Challenges | Where-Object { $_.Type -eq "http-01" }).ChallengeAnswer<br />$key = $challengeAnswer.Key<br />Write-Host ""<br />Write-Host "Create folder structure on $domain like so:"<br />Write-Host "$domain/$key"<br />Write-Host "Put an index.html file in that location that contains:"<br />Write-Host $challengeAnswer.Value</pre>
<p>Which outputs something like this:</p>
<pre>Create folder structure on cork.nl like so:<br />cork.nl/.well-known/acme-challenge/V6CPYDViDCk6X3YWC9wH61kKW2CHtQ-SLACnIcBNFPY<br />Put an index.html file in that location that contains:<br />V6CPYDViDCk6X3YWC9wH61kKW2CHtQ-SLACnIcBNFPY.8uMzTUtlJpLEsyNHnTmLutOPZyFv4VUCFwaqram0gRo</pre>
<p>I can do that! So what needs to happen is when the Let's Encrypt server goes to the URL <em>http://cork.nl/.well-known/acme-challenge/V6CPYDViDCk6X3YWC9wH61kKW2CHtQ-SLACnIcBNFPY</em> the body of the response should contain the secret key: <em>V6CPYDViDCk6X3YWC9wH61kKW2CHtQ-SLACnIcBNFPY.8uMzTUtlJpLEsyNHnTmLutOPZyFv4VUCFwaqram0gRo</em></p>
<p>In this case I do this by placing an index.html in the created folder as I know that IIS will serve that up by default, your server might be configured differently so make sure that it outputs the secret key somehow (and only the secret key, nothing else). </p>
<p>Right! Now we can tell Let's Encrypt: I'm ready, please verify:</p>
<pre>$challenge = Submit-ACMEChallenge -Ref dns1 -Challenge http-01<br />While ($challenge.Status -eq "pending") {<br />  Start-Sleep -m 500 # wait half a second before trying<br />  Write-Host "Status is still 'pending', waiting for it to change..."<br />  $challenge = Update-ACMEIdentifier -Ref dns1<br />}</pre>
<p>Here the challenge is submitted and it might take a second for the status to change from "pending" to "valid" so I ask for an update every half second before continuing.</p>
<p>When the status is "valid" we're golden, go get that cert now!</p>
<pre>New-ACMECertificate -Identifier dns1 -Alias cert1 -Generate<br />$certificateInfo = Submit-ACMECertificate -Ref cert1<br /><br />While([string]::IsNullOrEmpty($certificateInfo.IssuerSerialNumber)) {<br /> Start-Sleep -m 500 # wait half a second before trying<br /> Write-Host "IssuerSerialNumber is not set yet, waiting for it to be populated..."<br /> $certificateInfo = Update-ACMECertificate -Ref cert1<br />}<br /><br />Get-ACMECertificate -Ref cert1 -ExportPkcs12 cert1-all.pfx -CertificatePassword $certificiatePassword<br /><br />Write-Host "All done, there's a cert1-all.pfx file in $vault with password $certificiatePassword for you to use now"</pre>
<p>We're asking Let's Encrypt to generate the certificate and then we do another few pings for the IssuerSerialNumber to update, that's when the certificate has been completely generated. Finally we do a Get-ACMECertificate to receive it and it will be stored in the $vault folder. Note: I'm adding a password to this certificate but this functionality is not yet available in the 0.7.1 release of ACMESharp. Again, this was a specific need that I had for which I sent a pull request which was promptly accepted. </p>
<p>If all this sounds like a lot of work: it is not! </p>
<p>Now that you understand what's going on, this process is repeatable. Which is very necessary because <a href="https://letsencrypt.org/2015/11/09/why-90-days.html">by default these certificates expire every 90 days</a> and will expire even more quickly in the future. This is being done to promote security: a compromised certificate can now only be abused for a maximum of 90 days. It's also being done to promote automation: I built a PowerShell script so I can automate this, they achieved their goal!</p>
<p>The <a href="https://gist.github.com/nul800sebastiaan/31b000874ffa69f4c0af">full PS script is available in a gist</a> for you to copy and use.</p>
<p>Go forth and secure your sites!</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Extract dlls at runtime</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/extract-dlls-at-runtime/</link>
                <pubDate>Fri, 29 Aug 2014 18:39:28 GMT</pubDate>
                <guid>https://cultiv.nl/blog/extract-dlls-at-runtime/</guid>
                <description>
                    <![CDATA[<p>Okay, that's a geeky title, so I'll make it concrete: have you ever wanted to ship 1 dll that can target multiple API versions? Yeah, me too..!</p>
<p> </p>
<p> </p>
<p>Example: In Umbraco 7.1.5, we added some events that get triggered when Partial Views and Partial View Macros get added/saved/deleted through the tree in the backoffice. We wanted to subscribe to those events from Courier but of course that would mean that Courier version "x" would only work with Umbraco 7.1.5 and up. Trying to subscribe to events that don't exist in 7.1.4 would result in a beautiful YSOD. We don't really want to have the headache of deploying different versions of Courier for different versions of Umbraco.</p>
<p> </p>
<p>I suddenly remembered <a href="https://twitter.com/sitereactor">Morten</a> referring to a way to having a dll as an embedded resource which could be extracted on demand, he saw this clever little trick happening in <a href="https://github.com/tclem/libgit2sharp/pull/3">the libgit library</a>. So we'll have a look at the Umbraco version and if it's high enough, we'll extract the dll that can subscribe to those new events, if not, we'll just run the good old version and don't do anything else.</p>
<p> </p>
<p>So I ran with that and I can tell you: this works!</p>
<p> </p>
<p>There's a few steps:</p>
<p> </p>
<ul>
<li>Add the embedded resource to your solution and change it's path in the csproj file</li>
<li>During application startup, check the current Umbraco version and extract the file if possible</li>
<li>When we update the dll, make sure that it's extracted again</li>
</ul>
<p> </p>
<p>So we'll start with adding an embedded resource, which is pretty simple: right-click on the project you want to add the embedded dll to, go to Properties &gt; Resources &gt; Add Resource &gt; Find the file &gt; done.</p>
<p> </p>
<p>Now it gets a little trickier: we want the embedded resource to be updated every time we build the project, so that we always have the latest version of the embedded dll in our main dll. First of all you need to make sure that the build of your main dll depends on the build of the embedded dll. In your main project, right click the project &gt; Build Dependencies&gt; Project Dependencies and check on the project that builds your embedded dll.<br />Then we need to also make sure that this is not just a one-time copy that's being embedded (Visual Studio's default behavior) but that we refer to the path of the dll that's being built. Open up the csproj file of your main project in your favorite text editor and find the line where it says:</p>
<p> </p>
<pre>&lt;none Include="Resources\MyDllName.dll" /&gt;</pre>
<p> </p>
<p>Change that Include to the path of MyDllName.dll relative to that project directory, for example:</p>
<p> </p>
<pre>&lt;none Include="..\MyProjectName\bin\Debug\MyDllName.dll" /&gt;</pre>
<p> </p>
<p>Finally, update from "none" to:</p>
<p> </p>
<pre>&lt;EmbeddedResource Include="..\MyProjectName\bin\Debug\MyDllName.dll"/&gt;</pre>
<p> </p>
<p>Voilá, the biggest hurdle is taken. The rest is "just" code.</p>
<p> </p>
<p>We'll create a new Umbraco ApplicationEventHandler and try extract the embedded dll when the version of Umbraco is 7.1.5 or higher:</p>
<p> </p>
<pre>using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;
using Umbraco.Core;
using Umbraco.Core.Configuration;

namespace MyApp.ExampleNamespace
{
    internal class ExtractNewEventHandlers : ApplicationEventHandler
    {
        protected override void ApplicationInitialized(
               UmbracoApplicationBase umbracoApplication, 
               ApplicationContext applicationContext)
        {
            if (UmbracoVersion.Current &gt;= new Version(7, 1, 5))
                ExtractEventHandlers();
        }

        private void ExtractEventHandlers()
        {
            var fileName = Path.Combine(HttpRuntime.BinDirectory, 
                "MyDllName.dll");
            var fi = new FileInfo(fileName);
            
            try
            {
                (Assembly.GetEntryAssembly() ?? 
                    Assembly.GetExecutingAssembly())
                    .ExtractResourceToFile(
                        "MyApp.ExampleNamespace.MyDllName.dll",
                        fi.FullName);
            }
            catch (Exception ex)
            {
                if ((ex is AccessViolationException) == false &amp;&amp; 
                    (ex is IOException) == false)
                {
                    throw;
                }
            }
        }
    }
}
</pre>
<p> </p>
<p>The one tricky bit here is that the resource name is a bit weird: it's your default namespace (MyApp.ExampleNamespace) plus the full name of the file you've embedded (MyDllName.dll).</p>
<p> </p>
<p>Lastly, we have the extension method ExtractResourceToFile which does the extraction if the file doesn't exist or is different from an existing file.</p>
<p> </p>
<pre>using System;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;

namespace MyApp.ExampleNamespace
{
    internal static class AssemblyExtensions
    {
        public static bool ExtractResourceToFile(
            this Assembly assembly, string resourceName, 
            string outPath)
        {
            assembly = assembly ?? Assembly.GetExecutingAssembly();

            using (var resourceStream = 
                assembly.GetManifestResourceStream(resourceName))
            {
                var fi = new FileInfo(outPath);
                if (fi.Exists)
                {
                    using (var stream = File.OpenRead(outPath))
                    {
                        if (GetHash(stream)==GetHash(resourceStream))
                            return false;
                    }
                }

                using (var output = File.Create(outPath))
                {
                    int bytesRead;
                    var buf = new byte[4096];
                    resourceStream.Seek(0, SeekOrigin.Begin);
                    while ((bytesRead = resourceStream
                        .Read(buf, 0, buf.Length)) &gt; 0)
                    {
                        output.Write(buf, 0, bytesRead);
                    }
                }
            }

            return true;
        }

        internal static string GetHash(Stream stream)
        {
            var sha = new SHA256Managed();
            var hash = sha.ComputeHash(stream);
            return BitConverter.ToString(hash)
                .Replace("-", String.Empty);
        }
    }
}
</pre>
<p> </p>
<p>And that's about it. On each application pool start, we check if the hash of the file on disk is the same as the hash of the embedded resource, if so we do nothing, else we'll overwrite the file in the bin folder with the new embedded version. And if someone running this upgrades their Umbraco version: boom! They'll get the extra functionality from our embedded dll for free, automagically.</p>
<p> </p>
<p>I hope this might help some other people dealing with targeting multiple versions of APIs. However: remember that this is probably not so efficient for very large embedded resources. With great power comes great responsibility so before you go down this route make sure that this method is really what you want and need.</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Okay, that's a geeky title, so I'll make it concrete: have you ever wanted to ship 1 dll that can target multiple API versions? Yeah, me too..!</p>
<p> </p>
<p> </p>
<p>Example: In Umbraco 7.1.5, we added some events that get triggered when Partial Views and Partial View Macros get added/saved/deleted through the tree in the backoffice. We wanted to subscribe to those events from Courier but of course that would mean that Courier version "x" would only work with Umbraco 7.1.5 and up. Trying to subscribe to events that don't exist in 7.1.4 would result in a beautiful YSOD. We don't really want to have the headache of deploying different versions of Courier for different versions of Umbraco.</p>
<p> </p>
<p>I suddenly remembered <a href="https://twitter.com/sitereactor">Morten</a> referring to a way to having a dll as an embedded resource which could be extracted on demand, he saw this clever little trick happening in <a href="https://github.com/tclem/libgit2sharp/pull/3">the libgit library</a>. So we'll have a look at the Umbraco version and if it's high enough, we'll extract the dll that can subscribe to those new events, if not, we'll just run the good old version and don't do anything else.</p>
<p> </p>
<p>So I ran with that and I can tell you: this works!</p>
<p> </p>
<p>There's a few steps:</p>
<p> </p>
<ul>
<li>Add the embedded resource to your solution and change it's path in the csproj file</li>
<li>During application startup, check the current Umbraco version and extract the file if possible</li>
<li>When we update the dll, make sure that it's extracted again</li>
</ul>
<p> </p>
<p>So we'll start with adding an embedded resource, which is pretty simple: right-click on the project you want to add the embedded dll to, go to Properties &gt; Resources &gt; Add Resource &gt; Find the file &gt; done.</p>
<p> </p>
<p>Now it gets a little trickier: we want the embedded resource to be updated every time we build the project, so that we always have the latest version of the embedded dll in our main dll. First of all you need to make sure that the build of your main dll depends on the build of the embedded dll. In your main project, right click the project &gt; Build Dependencies&gt; Project Dependencies and check on the project that builds your embedded dll.<br />Then we need to also make sure that this is not just a one-time copy that's being embedded (Visual Studio's default behavior) but that we refer to the path of the dll that's being built. Open up the csproj file of your main project in your favorite text editor and find the line where it says:</p>
<p> </p>
<pre>&lt;none Include="Resources\MyDllName.dll" /&gt;</pre>
<p> </p>
<p>Change that Include to the path of MyDllName.dll relative to that project directory, for example:</p>
<p> </p>
<pre>&lt;none Include="..\MyProjectName\bin\Debug\MyDllName.dll" /&gt;</pre>
<p> </p>
<p>Finally, update from "none" to:</p>
<p> </p>
<pre>&lt;EmbeddedResource Include="..\MyProjectName\bin\Debug\MyDllName.dll"/&gt;</pre>
<p> </p>
<p>Voilá, the biggest hurdle is taken. The rest is "just" code.</p>
<p> </p>
<p>We'll create a new Umbraco ApplicationEventHandler and try extract the embedded dll when the version of Umbraco is 7.1.5 or higher:</p>
<p> </p>
<pre>using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;
using Umbraco.Core;
using Umbraco.Core.Configuration;

namespace MyApp.ExampleNamespace
{
    internal class ExtractNewEventHandlers : ApplicationEventHandler
    {
        protected override void ApplicationInitialized(
               UmbracoApplicationBase umbracoApplication, 
               ApplicationContext applicationContext)
        {
            if (UmbracoVersion.Current &gt;= new Version(7, 1, 5))
                ExtractEventHandlers();
        }

        private void ExtractEventHandlers()
        {
            var fileName = Path.Combine(HttpRuntime.BinDirectory, 
                "MyDllName.dll");
            var fi = new FileInfo(fileName);
            
            try
            {
                (Assembly.GetEntryAssembly() ?? 
                    Assembly.GetExecutingAssembly())
                    .ExtractResourceToFile(
                        "MyApp.ExampleNamespace.MyDllName.dll",
                        fi.FullName);
            }
            catch (Exception ex)
            {
                if ((ex is AccessViolationException) == false &amp;&amp; 
                    (ex is IOException) == false)
                {
                    throw;
                }
            }
        }
    }
}
</pre>
<p> </p>
<p>The one tricky bit here is that the resource name is a bit weird: it's your default namespace (MyApp.ExampleNamespace) plus the full name of the file you've embedded (MyDllName.dll).</p>
<p> </p>
<p>Lastly, we have the extension method ExtractResourceToFile which does the extraction if the file doesn't exist or is different from an existing file.</p>
<p> </p>
<pre>using System;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;

namespace MyApp.ExampleNamespace
{
    internal static class AssemblyExtensions
    {
        public static bool ExtractResourceToFile(
            this Assembly assembly, string resourceName, 
            string outPath)
        {
            assembly = assembly ?? Assembly.GetExecutingAssembly();

            using (var resourceStream = 
                assembly.GetManifestResourceStream(resourceName))
            {
                var fi = new FileInfo(outPath);
                if (fi.Exists)
                {
                    using (var stream = File.OpenRead(outPath))
                    {
                        if (GetHash(stream)==GetHash(resourceStream))
                            return false;
                    }
                }

                using (var output = File.Create(outPath))
                {
                    int bytesRead;
                    var buf = new byte[4096];
                    resourceStream.Seek(0, SeekOrigin.Begin);
                    while ((bytesRead = resourceStream
                        .Read(buf, 0, buf.Length)) &gt; 0)
                    {
                        output.Write(buf, 0, bytesRead);
                    }
                }
            }

            return true;
        }

        internal static string GetHash(Stream stream)
        {
            var sha = new SHA256Managed();
            var hash = sha.ComputeHash(stream);
            return BitConverter.ToString(hash)
                .Replace("-", String.Empty);
        }
    }
}
</pre>
<p> </p>
<p>And that's about it. On each application pool start, we check if the hash of the file on disk is the same as the hash of the embedded resource, if so we do nothing, else we'll overwrite the file in the bin folder with the new embedded version. And if someone running this upgrades their Umbraco version: boom! They'll get the extra functionality from our embedded dll for free, automagically.</p>
<p> </p>
<p>I hope this might help some other people dealing with targeting multiple versions of APIs. However: remember that this is probably not so efficient for very large embedded resources. With great power comes great responsibility so before you go down this route make sure that this method is really what you want and need.</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Umbraco tip of the week: give your editors less choice</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/umbraco-tip-of-the-week-give-your-editors-less-choice/</link>
                <pubDate>Fri, 31 Jan 2014 17:13:50 GMT</pubDate>
                <guid>https://cultiv.nl/blog/umbraco-tip-of-the-week-give-your-editors-less-choice/</guid>
                <description>
                    <![CDATA[<p>Choice is good, right? I'm a programmer, I'm a tinkerer, I'm a tweaker, I want as much choice as possible.. Except when it's silly, unneccessary choices. <a href="http://www.amazon.com/Dont-Make-Me-Think-Usability/dp/0321344758" target="_blank">Don't make me think</a>!</p>
<p>One of the Umbraco tips I always like to give people is to really think about how you build out the backoffice for your editors.<br />The editors are the actual customers to whom you're supposed to deliver value. They will be spending a huge amount of time in the backoffice and will hate you for every frustrating unneccessary choice that you give them.</p>
<p>Luckily, Umbraco gives you a lot of tools to help out with that so that the editors can enter content as easily as possible.&nbsp;</p>
<p>The one thing that I always hate seeing is the following:</p>
<p><img style="width: 227px; height: 293px; border: 1px solid black;" src="https://cultiv.nl/media/8336/2014-01-31_165211.png" alt="Some description" rel="227,293" /></p>
<p>Or:</p>
<p><img style="width: 500px; height: 356.67215815485997px;" src="https://cultiv.nl/media/8337/2014-01-31_170134.png" alt="Some description" rel="500,356.67215815485997" /></p>
<p>Can you spot what's wrong here?</p>
<p>How many times does your editor want to make a news area? In a normal site, there's usually only 1, right? Same for a blog, an FAQ area, and a contact page.</p>
<p>And under the news area you would only add content of type news item, correct? And under the blog, only items of type "blog post".</p>
<p>So why do you allow the FAQ Area under home when it's already been created? Here's a little secret: you don't have to!</p>
<p>Once you've created your news area, your blog and your FAQ area you can just disallow them again. Go to your "Home" document type and don't allow anything but the items your editors actually will be using.&nbsp;</p>
<p><img style="width: 430.63583815028903px; height: 500px; border: 1px solid black;" src="https://cultiv.nl/media/8338/2014-01-31_170609.png" alt="Some description" rel="430.63583815028903,500" /></p>
<p>So now when the editor tries to create something new, they can only make a relevant choice:</p>
<p><img style="width: 500px; height: 364.49399656946827px; border: 1px solid black;" src="https://cultiv.nl/media/8339/2014-01-31_170922.png" alt="Some description" rel="500,364.49399656946827" /></p>
<p>&nbsp;Notice that the blog overview is still there, the contact page is still there etc. And when you try to create new content under blog you can still only create blog posts.</p>
<p>So now you have full control over the site, you know that there's only <strong>one</strong> blog overview that you need to query for. The children of that blog overview will only ever contain blog posts. There's only one news area, containing only news items. Rinse and repeat.</p>
<p>On the other hand, your editors don't need to think about which item to pick when they click on "create". Less thinking helps them accomplish their tasks faster. If they have no choice then they don't need to be worried about doing the right thing, you've just helped them do it perfectly every time.</p>
<p><strong>Bonus tip:</strong> See how each type of document has it's own icon? That is another way to really add value to your sites, visual queues help your editor read less, thus think less, thus they can work faster and are happier with your wonderful site implementation.</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Choice is good, right? I'm a programmer, I'm a tinkerer, I'm a tweaker, I want as much choice as possible.. Except when it's silly, unneccessary choices. <a href="http://www.amazon.com/Dont-Make-Me-Think-Usability/dp/0321344758" target="_blank">Don't make me think</a>!</p>
<p>One of the Umbraco tips I always like to give people is to really think about how you build out the backoffice for your editors.<br />The editors are the actual customers to whom you're supposed to deliver value. They will be spending a huge amount of time in the backoffice and will hate you for every frustrating unneccessary choice that you give them.</p>
<p>Luckily, Umbraco gives you a lot of tools to help out with that so that the editors can enter content as easily as possible.&nbsp;</p>
<p>The one thing that I always hate seeing is the following:</p>
<p><img style="width: 227px; height: 293px; border: 1px solid black;" src="https://cultiv.nl/media/8336/2014-01-31_165211.png" alt="Some description" rel="227,293" /></p>
<p>Or:</p>
<p><img style="width: 500px; height: 356.67215815485997px;" src="https://cultiv.nl/media/8337/2014-01-31_170134.png" alt="Some description" rel="500,356.67215815485997" /></p>
<p>Can you spot what's wrong here?</p>
<p>How many times does your editor want to make a news area? In a normal site, there's usually only 1, right? Same for a blog, an FAQ area, and a contact page.</p>
<p>And under the news area you would only add content of type news item, correct? And under the blog, only items of type "blog post".</p>
<p>So why do you allow the FAQ Area under home when it's already been created? Here's a little secret: you don't have to!</p>
<p>Once you've created your news area, your blog and your FAQ area you can just disallow them again. Go to your "Home" document type and don't allow anything but the items your editors actually will be using.&nbsp;</p>
<p><img style="width: 430.63583815028903px; height: 500px; border: 1px solid black;" src="https://cultiv.nl/media/8338/2014-01-31_170609.png" alt="Some description" rel="430.63583815028903,500" /></p>
<p>So now when the editor tries to create something new, they can only make a relevant choice:</p>
<p><img style="width: 500px; height: 364.49399656946827px; border: 1px solid black;" src="https://cultiv.nl/media/8339/2014-01-31_170922.png" alt="Some description" rel="500,364.49399656946827" /></p>
<p>&nbsp;Notice that the blog overview is still there, the contact page is still there etc. And when you try to create new content under blog you can still only create blog posts.</p>
<p>So now you have full control over the site, you know that there's only <strong>one</strong> blog overview that you need to query for. The children of that blog overview will only ever contain blog posts. There's only one news area, containing only news items. Rinse and repeat.</p>
<p>On the other hand, your editors don't need to think about which item to pick when they click on "create". Less thinking helps them accomplish their tasks faster. If they have no choice then they don't need to be worried about doing the right thing, you've just helped them do it perfectly every time.</p>
<p><strong>Bonus tip:</strong> See how each type of document has it's own icon? That is another way to really add value to your sites, visual queues help your editor read less, thus think less, thus they can work faster and are happier with your wonderful site implementation.</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>What&#39;s this Umbraco route hijacking all about?</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/whats-this-umbraco-route-hijacking-all-about/</link>
                <pubDate>Mon, 27 Jan 2014 00:01:51 GMT</pubDate>
                <guid>https://cultiv.nl/blog/whats-this-umbraco-route-hijacking-all-about/</guid>
                <description>
                    <![CDATA[<p>So this site is now running on Umbraco 7 and has a snazzy new template. In order to make the homepage load a bit faster I thought it would be a good idea to introduce some paging so that the size of the page isn't so large.</p>
<p>I know I can hack paging as inline Razor script in the view but I thought I'd check out what the hype was all about with regards to <a href="http://our.umbraco.org/documentation/Reference/Mvc/custom-controllers" target="_blank">route hijacking</a>. </p>
<p>What is route hijacking? Well, it's a way to tell Umbraco that you want to add custom code to certain document types. It can be compared to using partial classes in webforms to insert your own code in masterpages (but better! ;)).</p>
<p>The blog posts are just children of the blog page, as noted <a href="/moving-from-datefolders-to-umbracos-new-listview/">in my previous article</a>. Which means that I just need a list of content items and do a bit of .Skip() and .Take() on them before rendering them on the page.</p>
<p>The examples in this post are very simple to keep it readable, but <a href="https://gist.github.com/nul800sebastiaan/8641249" target="_blank">the full examples are available in a Gist</a> as well.</p>
<p>So: this is MVC, which means I'll need three things, guess what they are?</p>
<h3>Model</h3>
<p>My model mainly consists of content, but also some properties to track the paging (total pages, current page, previous/next page number, etc). I can mix those in with the properties of the current page easily by making my model inherit from RenderBase and asking for the "CurrentPage" in the constructor method.</p>
<pre>using Umbraco.Web;
using Umbraco.Web.Models;

namespace Cultiv.Models
{
    public class BlogOverview : RenderModel
    {
        public BlogOverview(IPublishedContent content) : <br />          base(content) <br />        { }
        
        public int Page { get; set; }
        
        // More custom properties
    }
}</pre>
<h3>View</h3>
<p>The view will have access to all of our custom properties, one if which is the current page number (more on that later, in the controller). The output of the view below will be a header with the page number in it and the name of the current page (which will be "Blog" because this view is rendered on the "Blog" page).</p>
<p>I'm also using the layout that I've created for all the other pages, not using route hijacking. So everything is exactly the same except I have more properties to use. In the final version (not completely included for brevity, I can also do</p>
<pre>foreach(var post in Model.PagedBlogPosts) { //etc }</pre>
<p>Which is much nicer than</p>
<pre>foreach(var post in Model.Content.Children.OrderByDescending(c =&gt; c.CreateDate).Take(5).Skip(0)) { //etc }</pre>
<p>Note that in order for the view to understand whats going on, it needs to inherit from UmbracoViewPage with the type BlogOverview (again, this is the document type's alias). Here's an example of the view:</p>
<pre>@using Cultiv.Models
@inherits UmbracoViewPage&lt;BlogOverview&gt;
@{
    Layout = "~/Views/Site.cshtml";
}
&lt;h3&gt;This is page number @Model.Page&lt;/h3&gt;
&lt;p&gt;The current page's name is @Model.Content.Name&lt;/p&gt;</pre>
<h3>Controller</h3>
<p>I haven't explained how this route hijacking actually works. In this example, I'm making a controller with the same name as the document type's alias (BlogOverview). My template name is BlogOverview as well so the ActionResult method in this Controller is also named BlogOverview. In this case the document type alias and the template name are the same but if the template was named BlogPosts then the method would also need to be named BlogPosts.</p>
<p>Note that the Controller class name has to end with the world Controller (as usual with ASP.NET MVC) and inherit from Umbraco's RenderMvcController so that we get access to the current page and current template.</p>
<p>In this example I'll do some very simple processing: using model binding, the querystring value for the page number is set when the request comes in. If there's no querystring (?page=x is missing from the URL) then I'll set the current page number to 1. Remember I rendered the page number in my view earlier.</p>
<pre>using System.Web.Mvc;
using Cultiv.Models;
using Umbraco.Web.Mvc;

namespace Cultiv.Controllers
{
    public class BlogOverviewController : RenderMvcController
    {
        public ActionResult BlogOverview(RenderModel model)
        {<br />            var blogOverviewModel = new BlogOverview(model.Content);<br /><br />            if (blogOverviewModel.Page == 0) // default value for int
                blogOverviewModel.Page = 1;

            // do paging 

            return CurrentTemplate(blogOverviewModel);
        }
    }
}
</pre>
<p>For brevity's sake, I've left out the boring paging but as you can see if you go to the homepage of this site then the paging at the bottom actually works. ;-)</p>
<p>I hope this was helpful in showing when route hijacking can come in handy: if you want to do some processing on the server but want to keep your model simple, make sure to consider executing the code in a controller and keep your view very simple (or "dumb" as people like to say).</p>
<p>The full code for <a href="https://gist.github.com/nul800sebastiaan/8641249" target="_blank">the model view and controller are available in a Gist</a> for you to peruse.</p>
<p>Note: Yes, I know I could also have used a SurfaceController with a ChildActionOnly Index method and rendered that from my template but I like exploring and route hijacking was new to me. Works pretty well for my purposes here!</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>So this site is now running on Umbraco 7 and has a snazzy new template. In order to make the homepage load a bit faster I thought it would be a good idea to introduce some paging so that the size of the page isn't so large.</p>
<p>I know I can hack paging as inline Razor script in the view but I thought I'd check out what the hype was all about with regards to <a href="http://our.umbraco.org/documentation/Reference/Mvc/custom-controllers" target="_blank">route hijacking</a>. </p>
<p>What is route hijacking? Well, it's a way to tell Umbraco that you want to add custom code to certain document types. It can be compared to using partial classes in webforms to insert your own code in masterpages (but better! ;)).</p>
<p>The blog posts are just children of the blog page, as noted <a href="/moving-from-datefolders-to-umbracos-new-listview/">in my previous article</a>. Which means that I just need a list of content items and do a bit of .Skip() and .Take() on them before rendering them on the page.</p>
<p>The examples in this post are very simple to keep it readable, but <a href="https://gist.github.com/nul800sebastiaan/8641249" target="_blank">the full examples are available in a Gist</a> as well.</p>
<p>So: this is MVC, which means I'll need three things, guess what they are?</p>
<h3>Model</h3>
<p>My model mainly consists of content, but also some properties to track the paging (total pages, current page, previous/next page number, etc). I can mix those in with the properties of the current page easily by making my model inherit from RenderBase and asking for the "CurrentPage" in the constructor method.</p>
<pre>using Umbraco.Web;
using Umbraco.Web.Models;

namespace Cultiv.Models
{
    public class BlogOverview : RenderModel
    {
        public BlogOverview(IPublishedContent content) : <br />          base(content) <br />        { }
        
        public int Page { get; set; }
        
        // More custom properties
    }
}</pre>
<h3>View</h3>
<p>The view will have access to all of our custom properties, one if which is the current page number (more on that later, in the controller). The output of the view below will be a header with the page number in it and the name of the current page (which will be "Blog" because this view is rendered on the "Blog" page).</p>
<p>I'm also using the layout that I've created for all the other pages, not using route hijacking. So everything is exactly the same except I have more properties to use. In the final version (not completely included for brevity, I can also do</p>
<pre>foreach(var post in Model.PagedBlogPosts) { //etc }</pre>
<p>Which is much nicer than</p>
<pre>foreach(var post in Model.Content.Children.OrderByDescending(c =&gt; c.CreateDate).Take(5).Skip(0)) { //etc }</pre>
<p>Note that in order for the view to understand whats going on, it needs to inherit from UmbracoViewPage with the type BlogOverview (again, this is the document type's alias). Here's an example of the view:</p>
<pre>@using Cultiv.Models
@inherits UmbracoViewPage&lt;BlogOverview&gt;
@{
    Layout = "~/Views/Site.cshtml";
}
&lt;h3&gt;This is page number @Model.Page&lt;/h3&gt;
&lt;p&gt;The current page's name is @Model.Content.Name&lt;/p&gt;</pre>
<h3>Controller</h3>
<p>I haven't explained how this route hijacking actually works. In this example, I'm making a controller with the same name as the document type's alias (BlogOverview). My template name is BlogOverview as well so the ActionResult method in this Controller is also named BlogOverview. In this case the document type alias and the template name are the same but if the template was named BlogPosts then the method would also need to be named BlogPosts.</p>
<p>Note that the Controller class name has to end with the world Controller (as usual with ASP.NET MVC) and inherit from Umbraco's RenderMvcController so that we get access to the current page and current template.</p>
<p>In this example I'll do some very simple processing: using model binding, the querystring value for the page number is set when the request comes in. If there's no querystring (?page=x is missing from the URL) then I'll set the current page number to 1. Remember I rendered the page number in my view earlier.</p>
<pre>using System.Web.Mvc;
using Cultiv.Models;
using Umbraco.Web.Mvc;

namespace Cultiv.Controllers
{
    public class BlogOverviewController : RenderMvcController
    {
        public ActionResult BlogOverview(RenderModel model)
        {<br />            var blogOverviewModel = new BlogOverview(model.Content);<br /><br />            if (blogOverviewModel.Page == 0) // default value for int
                blogOverviewModel.Page = 1;

            // do paging 

            return CurrentTemplate(blogOverviewModel);
        }
    }
}
</pre>
<p>For brevity's sake, I've left out the boring paging but as you can see if you go to the homepage of this site then the paging at the bottom actually works. ;-)</p>
<p>I hope this was helpful in showing when route hijacking can come in handy: if you want to do some processing on the server but want to keep your model simple, make sure to consider executing the code in a controller and keep your view very simple (or "dumb" as people like to say).</p>
<p>The full code for <a href="https://gist.github.com/nul800sebastiaan/8641249" target="_blank">the model view and controller are available in a Gist</a> for you to peruse.</p>
<p>Note: Yes, I know I could also have used a SurfaceController with a ChildActionOnly Index method and rendered that from my template but I like exploring and route hijacking was new to me. Works pretty well for my purposes here!</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Moving from DateFolders to Umbraco&#39;s new ListView</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/moving-from-datefolders-to-umbracos-new-listview/</link>
                <pubDate>Sun, 19 Jan 2014 13:57:26 GMT</pubDate>
                <guid>https://cultiv.nl/blog/moving-from-datefolders-to-umbracos-new-listview/</guid>
                <description>
                    <![CDATA[<p>This site <span class="strikethrough">is currently still running on Umbraco 6.1.6 but I'm moving it over to Umbraco 7</span>, has moved from Umbraco 6.16 to v7 and I <span class="strikethrough">don't</span> didn't want to have my blog posts listed in date folders any more.</p>
<p>DateFolders were a bit of a hack to make sure that the tree in Umbraco could load quickly. Too many children under one single node would cause the expansion of the tree to slow down. Not only that, it's hard to find items if there's a long list under just one child.</p>
<p>The ListView in Umbraco 7 solves all that, it's a nice sortable, searchable and paged list of child items under the current node. In this screenshot, for example, there's three children under the currently selected node and they're shown in a list on the right side instead of in the tree on the left:</p>
<p><img src="https://cultiv.nl/media/8334/container_content_type_640x332_499x259.jpg" alt="Container _content _type _640x 332" width="499" height="259" /></p>
<p>So there were two challanges: moving all items and making sure the old URLs wouldn't start failing. </p>
<p>Redirecting the old URLs was actually the difficult part (since I suck at regex..). I used IIS' <a href="http://www.iis.net/downloads/microsoft/url-rewrite">URL Rewrite 2.0 extension</a> for this. This extension is not installed by default on all webservers, but in <em>Umbraco as a Service</em> (which is where this site lives) it is installed, nice!</p>
<p>So now to figure out the pattern: </p>
<ul>
<li>each blog post url starts with blog/</li>
<li>then a 4 digit year</li>
<li>then a 1 or 2 digit month</li>
<li>then a 1 or 2 digit day</li>
<li>then the blog title</li>
</ul>
<p>This leads to one group that includes the date and one group that contains the rest of the URL (groups are made by surrounding some arguments in parenthesis):</p>
<pre class="brush: c-sharp">(blog/\d{4}/\d{1,2}/\d{1,2}\/)(.*)</pre>
<p><br /> So once I got that one working, I added it to the web.config, in the rewrite/rules section. So: anything that starts with this regex pattern, do a permanent redirect to https://cultiv.nl/blog/{whatever-was-here-as-"the rest"-of-the-url} (R:2 refers to the second regex group, which is "(.*)" ):</p>
<pre class="brush: xml">&lt;rule name="Blog" stopProcessing="true"&gt;
	&lt;match url="^(blog/\d{4}/\d{1,2}/\d{1,2}\/)(.*)$" /&gt;
	&lt;action type="Redirect" url="https://cultiv.nl/blog/{R:2}" /&gt;
&lt;/rule&gt;</pre>
<p>Of course now all my URLs are failing because there's no actual content there, well let's fix that with a super simple <a href="http://our.umbraco.org/documentation/Reference/WebApi/">UmbracoApiController</a>. </p>
<p>Each of my blog posts has a content type with the alias of "BlogPost", these all need to be moved under the /blog node which has an Id of 1207. I can go through the descendants of anything under /blog and check the content type to see if it matches. <br />I also want to make sure that they're sorted from oldest to newest as that's the default sorting of Umbraco. With that done, I just move all posts directly under /blog. The new API in v6 make this so incredibly easy, awesome:</p>
<pre class="brush: c-sharp">using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Web.WebApi;

namespace Temporary.Controllers
{
    public class BlogPostsController : UmbracoApiController
    {
        public void PostMovePosts()
        {
            const int blogNodeId = 1207;

            var contentService = Services.ContentService;
            var blogNode = contentService.GetById(blogNodeId);

            foreach (var post in blogNode.Descendants().OrderBy(p =&gt; p.CreateDate))
            {
                if (post.ContentType.Alias == "BlogPost")
                {
                    contentService.Move(post, blogNodeId);
                }
            }
        }
    }
}
</pre>
<p>So: inherit from <em>UmbracoApiController</em>, that will create a route for us to go to: /umbraco/api/{ControllerName}/{MethodName} - So in this case: /umbraco/api/BlogPosts/PostMovePosts</p>
<p>By convention the BlogPostsController needs it's suffix "Controller" stripped off, so that turns in to "BlogPosts" and the method "PostMovePosts" starts with the verb "Post" which translates to the HTTP verb POST. That means I'll be using <a href="https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en">PostMan</a> with that verb:</p>
<p><img src="https://cultiv.nl/media/8332/2014-01-19_144340_499x270.jpg" alt="2014-01-19_144340" width="499" height="270" /></p>
<p>And there we have it, everything nicely moved and sorted, ready for the v7 upgrade.</p>
<p><img src="https://cultiv.nl/media/8333/2014-01-19_144517.png" alt="2014-01-19_144517" width="440" height="223" /></p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>This site <span class="strikethrough">is currently still running on Umbraco 6.1.6 but I'm moving it over to Umbraco 7</span>, has moved from Umbraco 6.16 to v7 and I <span class="strikethrough">don't</span> didn't want to have my blog posts listed in date folders any more.</p>
<p>DateFolders were a bit of a hack to make sure that the tree in Umbraco could load quickly. Too many children under one single node would cause the expansion of the tree to slow down. Not only that, it's hard to find items if there's a long list under just one child.</p>
<p>The ListView in Umbraco 7 solves all that, it's a nice sortable, searchable and paged list of child items under the current node. In this screenshot, for example, there's three children under the currently selected node and they're shown in a list on the right side instead of in the tree on the left:</p>
<p><img src="https://cultiv.nl/media/8334/container_content_type_640x332_499x259.jpg" alt="Container _content _type _640x 332" width="499" height="259" /></p>
<p>So there were two challanges: moving all items and making sure the old URLs wouldn't start failing. </p>
<p>Redirecting the old URLs was actually the difficult part (since I suck at regex..). I used IIS' <a href="http://www.iis.net/downloads/microsoft/url-rewrite">URL Rewrite 2.0 extension</a> for this. This extension is not installed by default on all webservers, but in <em>Umbraco as a Service</em> (which is where this site lives) it is installed, nice!</p>
<p>So now to figure out the pattern: </p>
<ul>
<li>each blog post url starts with blog/</li>
<li>then a 4 digit year</li>
<li>then a 1 or 2 digit month</li>
<li>then a 1 or 2 digit day</li>
<li>then the blog title</li>
</ul>
<p>This leads to one group that includes the date and one group that contains the rest of the URL (groups are made by surrounding some arguments in parenthesis):</p>
<pre class="brush: c-sharp">(blog/\d{4}/\d{1,2}/\d{1,2}\/)(.*)</pre>
<p><br /> So once I got that one working, I added it to the web.config, in the rewrite/rules section. So: anything that starts with this regex pattern, do a permanent redirect to https://cultiv.nl/blog/{whatever-was-here-as-"the rest"-of-the-url} (R:2 refers to the second regex group, which is "(.*)" ):</p>
<pre class="brush: xml">&lt;rule name="Blog" stopProcessing="true"&gt;
	&lt;match url="^(blog/\d{4}/\d{1,2}/\d{1,2}\/)(.*)$" /&gt;
	&lt;action type="Redirect" url="https://cultiv.nl/blog/{R:2}" /&gt;
&lt;/rule&gt;</pre>
<p>Of course now all my URLs are failing because there's no actual content there, well let's fix that with a super simple <a href="http://our.umbraco.org/documentation/Reference/WebApi/">UmbracoApiController</a>. </p>
<p>Each of my blog posts has a content type with the alias of "BlogPost", these all need to be moved under the /blog node which has an Id of 1207. I can go through the descendants of anything under /blog and check the content type to see if it matches. <br />I also want to make sure that they're sorted from oldest to newest as that's the default sorting of Umbraco. With that done, I just move all posts directly under /blog. The new API in v6 make this so incredibly easy, awesome:</p>
<pre class="brush: c-sharp">using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Web.WebApi;

namespace Temporary.Controllers
{
    public class BlogPostsController : UmbracoApiController
    {
        public void PostMovePosts()
        {
            const int blogNodeId = 1207;

            var contentService = Services.ContentService;
            var blogNode = contentService.GetById(blogNodeId);

            foreach (var post in blogNode.Descendants().OrderBy(p =&gt; p.CreateDate))
            {
                if (post.ContentType.Alias == "BlogPost")
                {
                    contentService.Move(post, blogNodeId);
                }
            }
        }
    }
}
</pre>
<p>So: inherit from <em>UmbracoApiController</em>, that will create a route for us to go to: /umbraco/api/{ControllerName}/{MethodName} - So in this case: /umbraco/api/BlogPosts/PostMovePosts</p>
<p>By convention the BlogPostsController needs it's suffix "Controller" stripped off, so that turns in to "BlogPosts" and the method "PostMovePosts" starts with the verb "Post" which translates to the HTTP verb POST. That means I'll be using <a href="https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en">PostMan</a> with that verb:</p>
<p><img src="https://cultiv.nl/media/8332/2014-01-19_144340_499x270.jpg" alt="2014-01-19_144340" width="499" height="270" /></p>
<p>And there we have it, everything nicely moved and sorted, ready for the v7 upgrade.</p>
<p><img src="https://cultiv.nl/media/8333/2014-01-19_144517.png" alt="2014-01-19_144517" width="440" height="223" /></p>]]>
                </content:encoded>
            </item>
            <item>
                <title>The CodeGarden Guide to Copenhagen</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/the-codegarden-guide-to-copenhagen/</link>
                <pubDate>Thu, 14 Feb 2013 16:46:20 GMT</pubDate>
                <guid>https://cultiv.nl/blog/the-codegarden-guide-to-copenhagen/</guid>
                <description>
                    <![CDATA[<p><span>A few years ago, </span><a href="https://twitter.com/sitereactor"><span>Morten</span></a><span> wrote </span><a href="http://blog.sitereactor.dk/2010/04/18/cg10-transport-and-hotel-guide"><span>a great blog post about coming to Copenhagen for CodeGarden</span></a><span>. Although I had been there the year before, I did learn a lot of things that were unclear to me the first time.</span><br /><br /><span>As you may or may know, Morten and I are now colleagues at Umbraco HQ and I actually moved to Denmark and I found some more tips to share for the people coming to </span><a href="http://umbraco.com/cg13"><span>Codegarden 13</span></a><span>.</span><br /><br /><span>CodeGarden is a </span><span>festival</span><span>, not just a tech conference. This means that there will be social interaction. As scary as that may sound to a nerd, you’ll soon feel right at home. </span></p>
<p><span>So the first thing I would recommend is: Don’t go home on Friday afternoon. There will be a lot of people going out for drinks and/or food on Friday and this is where you’ll not only talk more about the great stuff you’ve learned, but also a great opportunity to have a lot of fun.</span></p>
<h2>Public transport</h2>
<p><span>If you arrive in the airport, you have two options: the train to Copenhagen central station or the metro to one of the stops in the city center. Google Maps is excellent at telling you where you need to go in public transport, for example this is their advice for getting from the Cabinn hotel to the CodeGarden venue: </span><a href="http://goo.gl/maps/e8Enx"><span>http://goo.gl/maps/e8Enx</span></a><span>. On your smartphone there’s also the option to get directions for public transport, highly recommended.</span><br /><br /><span>When you come out of the gate, you walk straight ahead for about 200 meters and you can buy tickets (more on that in a minute) to the right side (either from the machine or at the booths).</span><br /><span>If you were to continue walking a little further, there’s an escalator going down on the left side, trains arriving there go to central station. If you want to take the metro however you go straight ahead upstairs and walk another 500 meters or so.</span></p>
<h3>Tickets</h3>
<p><span>I highly recommend getting a Flexcard for zones 1, 2 and 3. That should get you around most of Copenhagen for just 298DKK (ticket is valid for a week). zone 1 is city center, zone 2 is where the CodeGarden venue is and zone 3 is where the airport is.</span><br /><span>The other option is to get a “Klippekort” for 3 zones, you can have 10 rides on that one and it costs 200DKK. It’s a bit of a waste though, as you’ll mostly be travelling in zones 1 and 2.</span><br /><br /><span>The public transport site </span><a href="http://www.rejseplanen.dk/"><span>http://www.rejseplanen.dk/</span></a><span> has an English option. So it’s easy to plan your trips there ahead of time. They also have apps for smartphones that work great and can also be used in English.</span></p>
<h2>Other transport</h2>
<p><span>Taxi’s are pretty affordable in Copenhagen and they accept credit card payments for all major credit card companies. </span><br /><span>If you have your smartphone with you: </span><a href="http://www.clickataxi.com/"><span>Click A Taxi</span></a><span> is a really nice app for ordering a taxi at the place that you are right that moment. You’ll be waiting for about 5 minutes, most of the time even less.</span><br /><br /><span>But to get the full Copenhagen experience you should really rent a bicycle or use the free Copenhagen City Bikes: </span><a href="http://www.visitcopenhagen.com/transport/bike-city-copenhagen"><span>http://www.visitcopenhagen.com/transport/bike-city-copenhagen</span></a></p>
<h2>Hotels</h2>
<p><span>I’ll list some of the hotels that are popular:</span></p>
<ul>
<li><a href="https://www.cabinn.com/">https://www.cabinn.com/</a> - I usually stay here. It’s the cheapest option and they have the ugliest hotels. Rooms are clean and (let’s face it) all you really need is a bed and a warm shower, that’s what they provide (and not much more than that). Cabinn Express and Cabinn Scandinavia are really close to the CG13 venue as well.</li>
<li><a href="https://www.wakeupcopenhagen.com/">https://www.wakeupcopenhagen.com/</a> - Also a popular destination for CG attendees, I’ve not stayed there myself, but I hear it’s nice and clean.</li>
<li><a href="http://www.tivolihotel.dk/">http://www.tivolihotel.dk/</a> - Next to the WakeUp, it’s more luxurious and includes free ticket to amusement park Tivoli. It’s super nice, but you pay quite a bit more for it.</li>
</ul>
<ul>
<ul>
<li>Note: Both WakeUp and Tivoli hotel are pretty far away from the metro, so you’ll have to take busses, they’re fine but it’s a bit more difficult to know where you have to get on and off. The drivers are friendly though, ask them to warn you when they arrive at your stop.</li>
</ul>
<li><a href="http://www.operahotelcopenhagen.com/">http://www.operahotelcopenhagen.com/</a> - Opera is nice, it’s in the heart of Copenhagen near Nyhavn, a popular hangout for CodeGarden attendees, and also close to city center.</li>
<li><a href="http://www.brochner-hotels.dk/hotellerne/kong-arthur/">http://www.brochner-hotels.dk/hotellerne/kong-arthur/</a> - Also pretty luxureous and not very cheap. This hotel includes a spa that you can use any time you want.</li>
</ul>
<h2><br />Internet / 3G</h2>
<p><span>If you’re anything like me, you hate being in a strange city without Google Maps. At all post offices (there is one at Copenhagen central station) you will be able to buy and “Oister 1 uges” SIM card (not sure if they offer micro SIMs now) that you can use for one week. It include 10 gigs of data and it just 99DKK. The only tricky thing is that you need to activate it online. Here’s a guide I put together a few years ago: </span><a href="https://docs.google.com/a/sebastiaanjanssen.nl/document/d/1X-hwfdpjeYGKvS5RbI4W9DOVKWh8HpYjgt1kf7OQLxw/edit"><span>https://docs.google.com/a/sebastiaanjanssen.nl/document/d/1X-hwfdpjeYGKvS5RbI4W9DOVKWh8HpYjgt1kf7OQLxw/edit</span></a></p>
<h2>CodeGarden Venue</h2>
<p>CodeGarden is held at the beautiful <a href="http://www.visitcopenhagen.com/see-and-do/kedelhallen-frederiksberg/382">Kedelhallen</a> in the lovely Frederiksberg area of Copenhagen.</p>
<p><span>At the venue you should expect to get free coffee, tea and water. Lunch is provided and there’s a bar where you can buy snacks and other drinks if you like. Make sure to bring cash for that as not all cards are accepted at the bar.</span><br /><br /><span>Dinner is provided on the second day of CodeGarden where you will also be able to join the FAMOUS Umbraco Bingo with fantabulous prizes to be won.</span><br /><br /><span>In the neighborhood of the venue there’s also shops and little restaurants where you can have a meal if you want to get away from the nerds (but you will not want to, trust me).</span><br /><br /><span>There’s WiFi at the venue that usually works most of the time, but it will be slow and sometimes it just stops working until someone can reset the router. So only count on being able to tweet and definitely don’t expect to download that 20 megabyte Word file your colleague is sending you.</span><br /><br /><span>And that brings me to the last point: bring your laptop (there are power outlets you can use), but don’t sit with your laptop open all day. You’ll definitely miss out on the interaction and content of the sessions and that’s just a shame, there’s so many great things going on. Make sure you’re not needed for client work, your colleagues should know you’re at a festival, having a good time and learning loads. Make sure they don’t disturb your experience (as I said, it’s not a regular conference, there’s plenty going on to keep you occupied and learning).</span><br /><br /><span>Questions? Make sure to comment! Hope to see you in lovely Copenhagen this summer!</span></p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p><span>A few years ago, </span><a href="https://twitter.com/sitereactor"><span>Morten</span></a><span> wrote </span><a href="http://blog.sitereactor.dk/2010/04/18/cg10-transport-and-hotel-guide"><span>a great blog post about coming to Copenhagen for CodeGarden</span></a><span>. Although I had been there the year before, I did learn a lot of things that were unclear to me the first time.</span><br /><br /><span>As you may or may know, Morten and I are now colleagues at Umbraco HQ and I actually moved to Denmark and I found some more tips to share for the people coming to </span><a href="http://umbraco.com/cg13"><span>Codegarden 13</span></a><span>.</span><br /><br /><span>CodeGarden is a </span><span>festival</span><span>, not just a tech conference. This means that there will be social interaction. As scary as that may sound to a nerd, you’ll soon feel right at home. </span></p>
<p><span>So the first thing I would recommend is: Don’t go home on Friday afternoon. There will be a lot of people going out for drinks and/or food on Friday and this is where you’ll not only talk more about the great stuff you’ve learned, but also a great opportunity to have a lot of fun.</span></p>
<h2>Public transport</h2>
<p><span>If you arrive in the airport, you have two options: the train to Copenhagen central station or the metro to one of the stops in the city center. Google Maps is excellent at telling you where you need to go in public transport, for example this is their advice for getting from the Cabinn hotel to the CodeGarden venue: </span><a href="http://goo.gl/maps/e8Enx"><span>http://goo.gl/maps/e8Enx</span></a><span>. On your smartphone there’s also the option to get directions for public transport, highly recommended.</span><br /><br /><span>When you come out of the gate, you walk straight ahead for about 200 meters and you can buy tickets (more on that in a minute) to the right side (either from the machine or at the booths).</span><br /><span>If you were to continue walking a little further, there’s an escalator going down on the left side, trains arriving there go to central station. If you want to take the metro however you go straight ahead upstairs and walk another 500 meters or so.</span></p>
<h3>Tickets</h3>
<p><span>I highly recommend getting a Flexcard for zones 1, 2 and 3. That should get you around most of Copenhagen for just 298DKK (ticket is valid for a week). zone 1 is city center, zone 2 is where the CodeGarden venue is and zone 3 is where the airport is.</span><br /><span>The other option is to get a “Klippekort” for 3 zones, you can have 10 rides on that one and it costs 200DKK. It’s a bit of a waste though, as you’ll mostly be travelling in zones 1 and 2.</span><br /><br /><span>The public transport site </span><a href="http://www.rejseplanen.dk/"><span>http://www.rejseplanen.dk/</span></a><span> has an English option. So it’s easy to plan your trips there ahead of time. They also have apps for smartphones that work great and can also be used in English.</span></p>
<h2>Other transport</h2>
<p><span>Taxi’s are pretty affordable in Copenhagen and they accept credit card payments for all major credit card companies. </span><br /><span>If you have your smartphone with you: </span><a href="http://www.clickataxi.com/"><span>Click A Taxi</span></a><span> is a really nice app for ordering a taxi at the place that you are right that moment. You’ll be waiting for about 5 minutes, most of the time even less.</span><br /><br /><span>But to get the full Copenhagen experience you should really rent a bicycle or use the free Copenhagen City Bikes: </span><a href="http://www.visitcopenhagen.com/transport/bike-city-copenhagen"><span>http://www.visitcopenhagen.com/transport/bike-city-copenhagen</span></a></p>
<h2>Hotels</h2>
<p><span>I’ll list some of the hotels that are popular:</span></p>
<ul>
<li><a href="https://www.cabinn.com/">https://www.cabinn.com/</a> - I usually stay here. It’s the cheapest option and they have the ugliest hotels. Rooms are clean and (let’s face it) all you really need is a bed and a warm shower, that’s what they provide (and not much more than that). Cabinn Express and Cabinn Scandinavia are really close to the CG13 venue as well.</li>
<li><a href="https://www.wakeupcopenhagen.com/">https://www.wakeupcopenhagen.com/</a> - Also a popular destination for CG attendees, I’ve not stayed there myself, but I hear it’s nice and clean.</li>
<li><a href="http://www.tivolihotel.dk/">http://www.tivolihotel.dk/</a> - Next to the WakeUp, it’s more luxurious and includes free ticket to amusement park Tivoli. It’s super nice, but you pay quite a bit more for it.</li>
</ul>
<ul>
<ul>
<li>Note: Both WakeUp and Tivoli hotel are pretty far away from the metro, so you’ll have to take busses, they’re fine but it’s a bit more difficult to know where you have to get on and off. The drivers are friendly though, ask them to warn you when they arrive at your stop.</li>
</ul>
<li><a href="http://www.operahotelcopenhagen.com/">http://www.operahotelcopenhagen.com/</a> - Opera is nice, it’s in the heart of Copenhagen near Nyhavn, a popular hangout for CodeGarden attendees, and also close to city center.</li>
<li><a href="http://www.brochner-hotels.dk/hotellerne/kong-arthur/">http://www.brochner-hotels.dk/hotellerne/kong-arthur/</a> - Also pretty luxureous and not very cheap. This hotel includes a spa that you can use any time you want.</li>
</ul>
<h2><br />Internet / 3G</h2>
<p><span>If you’re anything like me, you hate being in a strange city without Google Maps. At all post offices (there is one at Copenhagen central station) you will be able to buy and “Oister 1 uges” SIM card (not sure if they offer micro SIMs now) that you can use for one week. It include 10 gigs of data and it just 99DKK. The only tricky thing is that you need to activate it online. Here’s a guide I put together a few years ago: </span><a href="https://docs.google.com/a/sebastiaanjanssen.nl/document/d/1X-hwfdpjeYGKvS5RbI4W9DOVKWh8HpYjgt1kf7OQLxw/edit"><span>https://docs.google.com/a/sebastiaanjanssen.nl/document/d/1X-hwfdpjeYGKvS5RbI4W9DOVKWh8HpYjgt1kf7OQLxw/edit</span></a></p>
<h2>CodeGarden Venue</h2>
<p>CodeGarden is held at the beautiful <a href="http://www.visitcopenhagen.com/see-and-do/kedelhallen-frederiksberg/382">Kedelhallen</a> in the lovely Frederiksberg area of Copenhagen.</p>
<p><span>At the venue you should expect to get free coffee, tea and water. Lunch is provided and there’s a bar where you can buy snacks and other drinks if you like. Make sure to bring cash for that as not all cards are accepted at the bar.</span><br /><br /><span>Dinner is provided on the second day of CodeGarden where you will also be able to join the FAMOUS Umbraco Bingo with fantabulous prizes to be won.</span><br /><br /><span>In the neighborhood of the venue there’s also shops and little restaurants where you can have a meal if you want to get away from the nerds (but you will not want to, trust me).</span><br /><br /><span>There’s WiFi at the venue that usually works most of the time, but it will be slow and sometimes it just stops working until someone can reset the router. So only count on being able to tweet and definitely don’t expect to download that 20 megabyte Word file your colleague is sending you.</span><br /><br /><span>And that brings me to the last point: bring your laptop (there are power outlets you can use), but don’t sit with your laptop open all day. You’ll definitely miss out on the interaction and content of the sessions and that’s just a shame, there’s so many great things going on. Make sure you’re not needed for client work, your colleagues should know you’re at a festival, having a good time and learning loads. Make sure they don’t disturb your experience (as I said, it’s not a regular conference, there’s plenty going on to keep you occupied and learning).</span><br /><br /><span>Questions? Make sure to comment! Hope to see you in lovely Copenhagen this summer!</span></p>]]>
                </content:encoded>
            </item>
            <item>
                <title>From 0 to Umbraco site in 60 seconds</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/from-0-to-umbraco-site-in-60-seconds/</link>
                <pubDate>Sat, 08 Sep 2012 16:26:25 GMT</pubDate>
                <guid>https://cultiv.nl/blog/from-0-to-umbraco-site-in-60-seconds/</guid>
                <description>
                    <![CDATA[<p>This screencast shows you how to get a fully functional Umbraco site up and running in 60 seconds. Make sure you have <a href="http://www.microsoft.com/web/webmatrix/">WebMatrix</a> installed.</p>
<p><iframe src="http://www.screenr.com/embed/tw68" width="650" height="396" frameborder="0"></iframe></p>
<p>&nbsp;</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>This screencast shows you how to get a fully functional Umbraco site up and running in 60 seconds. Make sure you have <a href="http://www.microsoft.com/web/webmatrix/">WebMatrix</a> installed.</p>
<p><iframe src="http://www.screenr.com/embed/tw68" width="650" height="396" frameborder="0"></iframe></p>
<p>&nbsp;</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>How to use ASP.NET Web API in Umbraco 4 &amp; .NET 4.0</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/how-to-use-aspnet-web-api-in-umbraco-4-net-40/</link>
                <pubDate>Thu, 28 Jun 2012 17:33:32 GMT</pubDate>
                <guid>https://cultiv.nl/blog/how-to-use-aspnet-web-api-in-umbraco-4-net-40/</guid>
                <description>
                    <![CDATA[<p>So, you really like the idea of the ASP.NET Web API and can't wait to use it? But you're using Umbraco 4 and / or Webforms? Good news everybody! It's super easy to use it.</p>
<p>First of all: Umbraco. It has a compiled global.asax out of the box and you can't actually go and extend it. In order to register the routing for the Web API you would normally have to edit the global.asax. Luckily, you can implement<strong>&nbsp;</strong>this easily using the System.Web.PreApplicationStartMethod.</p>
<p>So in Umbraco I have my Umbraco.Web project which is often completely uncompiled, so it's a Web Site Project instead of a Web Application Project (although I'm changing this). Next to that I usually have a seperate project called CustomerName.Extensions in which I add custom code that is compiled and the DLL ends up in Umbraco's bin folder.</p>
<p>Note: if you want to follow along, ASP.NET MVC 4 should be installed (it includes the Web API)&nbsp;on your machine (not in Umbraco) or you could install the <a href="http://nuget.org/packages/aspnetwebapi">Web API nuget package</a>.</p>
<p>In your (Umbraco) web project, you will also need a reference to Json.NET, again, just <a href="http://nuget.org/packages/newtonsoft.json">install the nuget package</a>.</p>
<p>To start with, I add references to that Extensions project:&nbsp;</p>
<ul>
<li>System.Web</li>
<li>System.Web.Http</li>
<li>System.Web.Http.WebHost</li>
</ul>
<p><span><br /></span>Then I add a class to register the API routes on startup, for me it looks like this:&nbsp;</p>
<pre class="brush: csharp">using System.Linq;
using System.Web.Routing;
using System.Web.Http;
using CustomerName.Extensions;

[assembly: System.Web.PreApplicationStartMethod(typeof(AppStart), "PreStart")]
namespace CustomerName.Extensions
{
public static class AppStart
{
public static void PreStart()
{
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
</pre>
<p>To test if the Web API bits work, add a new item to your project, I don't know about VS2010 but in VS2012 you can just find the Web API Controller Class right there.</p>
<p><img src="https://cultiv.nl/media/6627/2012-06-28_174756_500x294.jpg" alt="2012-06-28_174756" width="500" height="294" /></p>
<p>If you can't pick that one, then just make a new class and have it inherit from ApiController (as pictured above as well).</p>
<p>The default API Controller will give you some methods and you can immediately compile and check it out.</p>
<p>So in my case, I go to: http://mysite.local/api/values and get a lovely XML feed:</p>
<p><img src="https://cultiv.nl/media/6633/c36x_497x150.jpg" alt="C 36x" width="497" height="150" /></p>
<p>And.. that's all there is to it!</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>So, you really like the idea of the ASP.NET Web API and can't wait to use it? But you're using Umbraco 4 and / or Webforms? Good news everybody! It's super easy to use it.</p>
<p>First of all: Umbraco. It has a compiled global.asax out of the box and you can't actually go and extend it. In order to register the routing for the Web API you would normally have to edit the global.asax. Luckily, you can implement<strong>&nbsp;</strong>this easily using the System.Web.PreApplicationStartMethod.</p>
<p>So in Umbraco I have my Umbraco.Web project which is often completely uncompiled, so it's a Web Site Project instead of a Web Application Project (although I'm changing this). Next to that I usually have a seperate project called CustomerName.Extensions in which I add custom code that is compiled and the DLL ends up in Umbraco's bin folder.</p>
<p>Note: if you want to follow along, ASP.NET MVC 4 should be installed (it includes the Web API)&nbsp;on your machine (not in Umbraco) or you could install the <a href="http://nuget.org/packages/aspnetwebapi">Web API nuget package</a>.</p>
<p>In your (Umbraco) web project, you will also need a reference to Json.NET, again, just <a href="http://nuget.org/packages/newtonsoft.json">install the nuget package</a>.</p>
<p>To start with, I add references to that Extensions project:&nbsp;</p>
<ul>
<li>System.Web</li>
<li>System.Web.Http</li>
<li>System.Web.Http.WebHost</li>
</ul>
<p><span><br /></span>Then I add a class to register the API routes on startup, for me it looks like this:&nbsp;</p>
<pre class="brush: csharp">using System.Linq;
using System.Web.Routing;
using System.Web.Http;
using CustomerName.Extensions;

[assembly: System.Web.PreApplicationStartMethod(typeof(AppStart), "PreStart")]
namespace CustomerName.Extensions
{
public static class AppStart
{
public static void PreStart()
{
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
</pre>
<p>To test if the Web API bits work, add a new item to your project, I don't know about VS2010 but in VS2012 you can just find the Web API Controller Class right there.</p>
<p><img src="https://cultiv.nl/media/6627/2012-06-28_174756_500x294.jpg" alt="2012-06-28_174756" width="500" height="294" /></p>
<p>If you can't pick that one, then just make a new class and have it inherit from ApiController (as pictured above as well).</p>
<p>The default API Controller will give you some methods and you can immediately compile and check it out.</p>
<p>So in my case, I go to: http://mysite.local/api/values and get a lovely XML feed:</p>
<p><img src="https://cultiv.nl/media/6633/c36x_497x150.jpg" alt="C 36x" width="497" height="150" /></p>
<p>And.. that's all there is to it!</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Tip of the week: Clean those ASP.NET temp files</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/tip-of-the-week-clean-those-aspnet-temp-files/</link>
                <pubDate>Fri, 13 Apr 2012 13:52:45 GMT</pubDate>
                <guid>https://cultiv.nl/blog/tip-of-the-week-clean-those-aspnet-temp-files/</guid>
                <description>
                    <![CDATA[<p>One of the things that Umbraco 5 plugin developers have been struggling with from day 1 is ASP.NET aggressive caching of their assemblies. As it appears, after you build your plugin code and put the new dll into the plugins folder, many times the new code will not be used. Instead, you get the stale cached version and that's very unproductive.</p>
<p>Shannon did a <a href="http://shazwazza.com/post/Taming-the-BuildManager-ASPNet-Temp-files-and-AppDomain-restarts.aspx"> lot of great research</a> last month focussing on just this problem and I'm happy to see that these problems might become obsolete in one of the upcoming versions of Umbraco 5.</p>
<p>From what I've distilled from his blogpost though, there's a very easy way to forces ASP.NET to clear the cache: touch the global.asax instead of the web.config.&nbsp;</p>
<p>One thing that has bothered me for YEARS now is that I have to go into the web.config, add a space, save, etc. Today I realized that it would be so easy to automate this.</p>
<p>A quick search return <a href="http://www.softtreetech.com/24x7/archive/47.htm">a tiny utility called FileTouch</a> that does what it says on the tin: change the modify date (or create date, or access date) of a file.</p>
<p>So I made a tiny little batch file that does just that for me:&nbsp;</p>
<p><strong>FileTouch .\Umbraco.Web\Global.asax</strong></p>
<p>That's all! I found the temp folder of the site I'm currently working on, executed the above command line and once I try to access the site again I see everything disappearing from the ASP.NET temp folder quickly and new files being put in that equally fast.</p>
<p>You could also make this an afterbuild event in your project but I don't always want the extra hit (rebuilding the cache takes a little extra time), so I prefer to just have the command line open and executing the batch file whenever I think I'll need it.</p>
<p><em>Foto courtesy of:&nbsp;<a href="http://www.flickr.com/photos/emilyrides/5188289325/">http://www.flickr.com/photos/emilyrides/5188289325/</a></em></p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>One of the things that Umbraco 5 plugin developers have been struggling with from day 1 is ASP.NET aggressive caching of their assemblies. As it appears, after you build your plugin code and put the new dll into the plugins folder, many times the new code will not be used. Instead, you get the stale cached version and that's very unproductive.</p>
<p>Shannon did a <a href="http://shazwazza.com/post/Taming-the-BuildManager-ASPNet-Temp-files-and-AppDomain-restarts.aspx"> lot of great research</a> last month focussing on just this problem and I'm happy to see that these problems might become obsolete in one of the upcoming versions of Umbraco 5.</p>
<p>From what I've distilled from his blogpost though, there's a very easy way to forces ASP.NET to clear the cache: touch the global.asax instead of the web.config.&nbsp;</p>
<p>One thing that has bothered me for YEARS now is that I have to go into the web.config, add a space, save, etc. Today I realized that it would be so easy to automate this.</p>
<p>A quick search return <a href="http://www.softtreetech.com/24x7/archive/47.htm">a tiny utility called FileTouch</a> that does what it says on the tin: change the modify date (or create date, or access date) of a file.</p>
<p>So I made a tiny little batch file that does just that for me:&nbsp;</p>
<p><strong>FileTouch .\Umbraco.Web\Global.asax</strong></p>
<p>That's all! I found the temp folder of the site I'm currently working on, executed the above command line and once I try to access the site again I see everything disappearing from the ASP.NET temp folder quickly and new files being put in that equally fast.</p>
<p>You could also make this an afterbuild event in your project but I don't always want the extra hit (rebuilding the cache takes a little extra time), so I prefer to just have the command line open and executing the batch file whenever I think I'll need it.</p>
<p><em>Foto courtesy of:&nbsp;<a href="http://www.flickr.com/photos/emilyrides/5188289325/">http://www.flickr.com/photos/emilyrides/5188289325/</a></em></p>]]>
                </content:encoded>
            </item>
            <item>
                <title>ASP.NET Web Api is silly easy</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/aspnet-web-api-is-silly-easy/</link>
                <pubDate>Fri, 30 Mar 2012 18:40:10 GMT</pubDate>
                <guid>https://cultiv.nl/blog/aspnet-web-api-is-silly-easy/</guid>
                <description>
                    <![CDATA[<p>... Well: silly easy if you don't have too many requirements, but I did. Good news though: solved my problems in under 2 hours.</p>
<p>What is the ASP.NET Web API? Well, according to <a href="http://www.asp.net/web-api">Microsoft</a>: "<span><em>ASP.NET Web API is a framework that makes it easy to build HTTP services that reach a broad range of clients, including browsers and mobile devices. ASP.NET Web API is an ideal platform for building RESTful applications on the .NET Framework.</em>"</span></p>
<p>When I saw the demo at the TechDays last month, I formulated the following explenation: Anything that returns IEnumerable can now be accessed as XML/JSON and anything IQueryable can be queried with OData syntax; very <strong>very</strong> easily.</p>
<p>Here's what I had to do to go from a MVC3 site that uses Ninject for dependency injection to a MVC4 site that can answer to Web API calls.</p>
<p>First of all, I had to upgrade my solution to MVC4. The asp.net site provides <a href="http://www.asp.net/whitepapers/mvc4-release-notes#_Toc303253806"> detailed upgrade instructions</a> that just work.</p>
<p>Next, I installed <a href="http://www.nuget.org/packages/WebApi.All">Web API NuGet package</a> into my existing web project. For some reason, the routing was not updated so in my global.asax.cs I had to add the route like so:</p>
<pre class="brush: c-sharp">routes.MapHttpRoute("Default API Route",
"api/1.0/{controller}/{id}",
new { id = RouteParameter.Optional });
</pre>
<p>I think it's pretty self-explanatory that any ApiController I will add can be resolved through the URL /api/1.0/MyControllerName.</p>
<p>In the VS11 tooling (I don't know if this works with VS2010) I can now add a new controller of type API controller. If it doesn't work in VS2010, just create a new controller and inherit from ApiController instead of Controller.</p>
<p><img src="https://cultiv.nl/media/6196/2012-03-30_185208_499x325.jpg" alt="2012-03-30_185208" width="499" height="325" /></p>
<p>Just running the default code for this worked fine, but of course I wanted to use Web API to access some of my existing database content.</p>
<p>So I added a constructor that accepted a IInfoService class and set up a field for it so it could be injected by Ninject. Well.. *BOOM* that didn't work, error:</p>
<p><strong>The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.</strong></p>
<p>Well, after a bit of Googling the answer was provided by Phil Haack: <a href="http://haacked.com/archive/2012/03/11/itrsquos-the-little-things-about-asp-net-mvc-4.aspx"> You need to configure a dependency resolver for Web API</a>. To add to the class he posted there, I had to have these usings in place to make it work (make sure to use System.Web.Http.Services instead of System.Web.Mvc):&nbsp;</p>
<pre class="brush: c-sharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http.Services;
</pre>
<p>Perfect! Or so I thought.. Now when trying to call into the API, something was wrong with the serialization of my object due to the following error:</p>
<p><strong>The type 'MyType' cannot be serialized to JSON because its IsReference setting is 'True'. The JSON format does not support references because there is no standardized format for representing references. To enable serialization, disable the IsReference setting on the type or an appropriate parent class of the type.</strong></p>
<p>Another round of Googling and I found out that the default Microsof serializer does not support my type of object. Problem is, I can't just change my class either. So in comes my favourite <a href="http://nuget.org/packages/newtonsoft.json">Javascript serializer: Json.NET</a>. Another quick NuGet install and then I had to <a href="http://blogs.msdn.com/b/henrikn/archive/2012/02/18/using-json-net-with-asp-net-web-api.aspx"> replace the default MS serializer with Json.NET</a>.</p>
<p>The blog post in the last link is actually missing and important piece for me with my Web Application project (it refers to a self-hosted controller, I'm hosting my controllers in my Application!). So, using the JsonFormatter class, I added the following to my global.asax.cs:</p>
<pre class="brush: c-sharp">// Create Json.Net formatter serializing DateTime using the ISO 8601 format
var serializerSettings = new JsonSerializerSettings();
serializerSettings.Converters.Add(new IsoDateTimeConverter());
var jsonNetFormatter = new JsonNetFormatter(serializerSettings);
var index = GlobalConfiguration.Configuration.Formatters.IndexOf(GlobalConfiguration.Configuration.Formatters.JsonFormatter);
GlobalConfiguration.Configuration.Formatters.RemoveAt(index);
GlobalConfiguration.Configuration.Formatters.Insert(index, jsonNetFormatter);
</pre>
<p>And there you have it, now when I run the Web API call I get an actual beautiful JSON object back and if you look at the url, I even did some oData querying, because I could! My Get() function returns an IQueryable, from which you get oData querying automatically, awesome!</p>
<p><img src="https://cultiv.nl/media/6202/2012-03-30_192652_500x383.jpg" alt="2012-03-30_192652" width="500" height="383" /></p>
<p>Of course, if you start with a MVC4 project in the future then most of this will be solved for you. I fully expect Ninject to do some updates so that their NuGet package will just make this work. The only thing that you might need to do is use Json.NET sometimes if you have unsupported objects that can't be changed.</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>... Well: silly easy if you don't have too many requirements, but I did. Good news though: solved my problems in under 2 hours.</p>
<p>What is the ASP.NET Web API? Well, according to <a href="http://www.asp.net/web-api">Microsoft</a>: "<span><em>ASP.NET Web API is a framework that makes it easy to build HTTP services that reach a broad range of clients, including browsers and mobile devices. ASP.NET Web API is an ideal platform for building RESTful applications on the .NET Framework.</em>"</span></p>
<p>When I saw the demo at the TechDays last month, I formulated the following explenation: Anything that returns IEnumerable can now be accessed as XML/JSON and anything IQueryable can be queried with OData syntax; very <strong>very</strong> easily.</p>
<p>Here's what I had to do to go from a MVC3 site that uses Ninject for dependency injection to a MVC4 site that can answer to Web API calls.</p>
<p>First of all, I had to upgrade my solution to MVC4. The asp.net site provides <a href="http://www.asp.net/whitepapers/mvc4-release-notes#_Toc303253806"> detailed upgrade instructions</a> that just work.</p>
<p>Next, I installed <a href="http://www.nuget.org/packages/WebApi.All">Web API NuGet package</a> into my existing web project. For some reason, the routing was not updated so in my global.asax.cs I had to add the route like so:</p>
<pre class="brush: c-sharp">routes.MapHttpRoute("Default API Route",
"api/1.0/{controller}/{id}",
new { id = RouteParameter.Optional });
</pre>
<p>I think it's pretty self-explanatory that any ApiController I will add can be resolved through the URL /api/1.0/MyControllerName.</p>
<p>In the VS11 tooling (I don't know if this works with VS2010) I can now add a new controller of type API controller. If it doesn't work in VS2010, just create a new controller and inherit from ApiController instead of Controller.</p>
<p><img src="https://cultiv.nl/media/6196/2012-03-30_185208_499x325.jpg" alt="2012-03-30_185208" width="499" height="325" /></p>
<p>Just running the default code for this worked fine, but of course I wanted to use Web API to access some of my existing database content.</p>
<p>So I added a constructor that accepted a IInfoService class and set up a field for it so it could be injected by Ninject. Well.. *BOOM* that didn't work, error:</p>
<p><strong>The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.</strong></p>
<p>Well, after a bit of Googling the answer was provided by Phil Haack: <a href="http://haacked.com/archive/2012/03/11/itrsquos-the-little-things-about-asp-net-mvc-4.aspx"> You need to configure a dependency resolver for Web API</a>. To add to the class he posted there, I had to have these usings in place to make it work (make sure to use System.Web.Http.Services instead of System.Web.Mvc):&nbsp;</p>
<pre class="brush: c-sharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http.Services;
</pre>
<p>Perfect! Or so I thought.. Now when trying to call into the API, something was wrong with the serialization of my object due to the following error:</p>
<p><strong>The type 'MyType' cannot be serialized to JSON because its IsReference setting is 'True'. The JSON format does not support references because there is no standardized format for representing references. To enable serialization, disable the IsReference setting on the type or an appropriate parent class of the type.</strong></p>
<p>Another round of Googling and I found out that the default Microsof serializer does not support my type of object. Problem is, I can't just change my class either. So in comes my favourite <a href="http://nuget.org/packages/newtonsoft.json">Javascript serializer: Json.NET</a>. Another quick NuGet install and then I had to <a href="http://blogs.msdn.com/b/henrikn/archive/2012/02/18/using-json-net-with-asp-net-web-api.aspx"> replace the default MS serializer with Json.NET</a>.</p>
<p>The blog post in the last link is actually missing and important piece for me with my Web Application project (it refers to a self-hosted controller, I'm hosting my controllers in my Application!). So, using the JsonFormatter class, I added the following to my global.asax.cs:</p>
<pre class="brush: c-sharp">// Create Json.Net formatter serializing DateTime using the ISO 8601 format
var serializerSettings = new JsonSerializerSettings();
serializerSettings.Converters.Add(new IsoDateTimeConverter());
var jsonNetFormatter = new JsonNetFormatter(serializerSettings);
var index = GlobalConfiguration.Configuration.Formatters.IndexOf(GlobalConfiguration.Configuration.Formatters.JsonFormatter);
GlobalConfiguration.Configuration.Formatters.RemoveAt(index);
GlobalConfiguration.Configuration.Formatters.Insert(index, jsonNetFormatter);
</pre>
<p>And there you have it, now when I run the Web API call I get an actual beautiful JSON object back and if you look at the url, I even did some oData querying, because I could! My Get() function returns an IQueryable, from which you get oData querying automatically, awesome!</p>
<p><img src="https://cultiv.nl/media/6202/2012-03-30_192652_500x383.jpg" alt="2012-03-30_192652" width="500" height="383" /></p>
<p>Of course, if you start with a MVC4 project in the future then most of this will be solved for you. I fully expect Ninject to do some updates so that their NuGet package will just make this work. The only thing that you might need to do is use Json.NET sometimes if you have unsupported objects that can't be changed.</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Tip of the week: ReSharper Code Templates</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/tip-of-the-week-resharper-code-templates/</link>
                <pubDate>Sun, 18 Mar 2012 08:39:04 GMT</pubDate>
                <guid>https://cultiv.nl/blog/tip-of-the-week-resharper-code-templates/</guid>
                <description>
                    <![CDATA[<p>Last Friday I was explaining to a colleague that I can never remember how I write the jQuery document ready function. Instead I always:</p>
<ol>
<li>Go to cultiv.nl/blog</li>
<li>Find the blog post of which I can never remember the title but it has a black icon of a t-shirt with json on it</li>
<li>Scroll down to the comments</li>
<li>Find <a href="https://cultiv.nl/blog/2010/10/12/using-base-to-create-and-consume-a-json-string/#comment-1325"> the comment by Aaron</a></li>
<li>Copy &amp; paste&nbsp;$(function() { ...&nbsp;});</li>
<li>Remove the dots</li>
<li>Move the&nbsp;}); to the end of whatever I'm surrounding with document ready</li>
<li>CTRL+K, D to reformat the file</li>
</ol>
<p><br /> Tedious!&nbsp;There's a better way to do this though.</p>
<p>I use ReSharper a lot and it offers a few things to surround a selected piece of code with. Out of the box, in Javascript you can only surround it with {} or (). Nice but not very useful.&nbsp;</p>
<p>Luckily, you can add your own "surround with" templates:</p>
<ol>
<li>Go to ReSharper &gt; Templates Explorer...</li>
<li>Go to the Surround Templates tab</li>
<li>Go to Javascript and hit the New Template button</li>
<li>Give it a title and edit the template slightly:<br /> <img src="https://cultiv.nl/media/6054/2012-03-18_084915.png" alt="2012-03-18_084915" width="266" height="183" /></li>
<li>Done!</li>
</ol>
<p><br /> Now I can just go to my javascript file and select a bit of code, hit the Surround With shortcut (for me CTRL+E,U) and get my new option:</p>
<p><img src="https://cultiv.nl/media/6060/2012-03-18_085129.png" alt="2012-03-18_085129" width="276" height="166" /></p>
<p>And after hitting return (or "1") my document ready log is properly surrounded:</p>
<p><img src="https://cultiv.nl/media/6066/2012-03-18_085218.png" alt="2012-03-18_085218" width="318" height="151" /></p>
<p>From now on, I'll be paying more attention to repetitive tasks and constructs I can never seem to remember and making some <a href="http://www.jetbrains.com/resharper/features/code_templates.html"> cool Code Templates</a> where I can.</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Last Friday I was explaining to a colleague that I can never remember how I write the jQuery document ready function. Instead I always:</p>
<ol>
<li>Go to cultiv.nl/blog</li>
<li>Find the blog post of which I can never remember the title but it has a black icon of a t-shirt with json on it</li>
<li>Scroll down to the comments</li>
<li>Find <a href="https://cultiv.nl/blog/2010/10/12/using-base-to-create-and-consume-a-json-string/#comment-1325"> the comment by Aaron</a></li>
<li>Copy &amp; paste&nbsp;$(function() { ...&nbsp;});</li>
<li>Remove the dots</li>
<li>Move the&nbsp;}); to the end of whatever I'm surrounding with document ready</li>
<li>CTRL+K, D to reformat the file</li>
</ol>
<p><br /> Tedious!&nbsp;There's a better way to do this though.</p>
<p>I use ReSharper a lot and it offers a few things to surround a selected piece of code with. Out of the box, in Javascript you can only surround it with {} or (). Nice but not very useful.&nbsp;</p>
<p>Luckily, you can add your own "surround with" templates:</p>
<ol>
<li>Go to ReSharper &gt; Templates Explorer...</li>
<li>Go to the Surround Templates tab</li>
<li>Go to Javascript and hit the New Template button</li>
<li>Give it a title and edit the template slightly:<br /> <img src="https://cultiv.nl/media/6054/2012-03-18_084915.png" alt="2012-03-18_084915" width="266" height="183" /></li>
<li>Done!</li>
</ol>
<p><br /> Now I can just go to my javascript file and select a bit of code, hit the Surround With shortcut (for me CTRL+E,U) and get my new option:</p>
<p><img src="https://cultiv.nl/media/6060/2012-03-18_085129.png" alt="2012-03-18_085129" width="276" height="166" /></p>
<p>And after hitting return (or "1") my document ready log is properly surrounded:</p>
<p><img src="https://cultiv.nl/media/6066/2012-03-18_085218.png" alt="2012-03-18_085218" width="318" height="151" /></p>
<p>From now on, I'll be paying more attention to repetitive tasks and constructs I can never seem to remember and making some <a href="http://www.jetbrains.com/resharper/features/code_templates.html"> cool Code Templates</a> where I can.</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Razor vs. &quot;/base&quot; to output Json in Umbraco</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/razor-vs-base-to-output-json-in-umbraco/</link>
                <pubDate>Mon, 25 Jul 2011 09:52:57 GMT</pubDate>
                <guid>https://cultiv.nl/blog/razor-vs-base-to-output-json-in-umbraco/</guid>
                <description>
                    <![CDATA[<p>A few months ago I posted about <a href="https://cultiv.nl/blog/using-base-to-create-and-consume-a-json-string/" title="Using &quot;/base&quot; to create and consume a JSON string"> outputting javascript objects (Json) using an umbraco's "/base"</a>. As you might've noticed, I've been becoming a fan of using Razor in Umbraco and had a bit of an epiphany the other day: why not use Razor to create my Json strings!</p>
<p>So, to do this, I created a new template, let's call it "RazorJson" and add a new macro on it:</p>
<pre class="brush: xml">&lt;umbraco:Macro FileLocation="~/macroScripts/give-me-json.cshtml" runat="server" /&gt;
</pre>
<p>It's important to remember that, in Umbraco, you don't have to create a new page that actually uses this template, if there's no URL conflicts (a node in the root of the site is not called RazorJson), then you can call a template directly. <em>Do note that that context in this case will be the home page (more on that later).</em>&nbsp;</p>
<p>By going to http://mysite.com/RazorJson I get to see my newly created template, but because it is still empty at the moment I get a blank screen.&nbsp;</p>
<p>Let's say that I want to output the current node's properties in Json, we can just do something very simple like this:</p>
<pre class="brush: c-sharp">@{
var node = new umbraco.NodeFactory.Node(Model.Id);
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
}<br />
@Html.Raw(serializer.Serialize(node.Properties))
</pre>
<p>So we're taking the current node's Id (Model.Id) and instantiate a new Node() from it. Then it's properties gets serialized into a Json string and that is what's being shown on the page.&nbsp;</p>
<p>Presto!</p>
<p><img src="https://cultiv.nl/media/5119/2011-07-25_104816_498x235.jpg" alt="2011-07-25_104816" width="498" height="235" /></p>
<p>Now, to make it a bit more interesting, remember how I said this page would only run in the home page's context? You could just turn any of your pages into a Json object by going to, for example, http://mysite.com/about?altTemplate=RazorJson<br /> This will render the "about" page with the RazorJson template and therefore output all of the "about" page's properties in Json notation.</p>
<p>I tweeted about this and got some comments, among which this one:</p>
<p><a href="http://twitter.com/#!/agrath/status/94346353345441792"><img src="https://cultiv.nl/media/5080/2011-07-25_102146_499x265.jpg" alt="2011-07-25_102146" width="499" height="265" /></a></p>
<p>Gareth is right, to create a /base extension, you write a seperate class that handles your businesslogic for you and /base just outputs either XML or a string.</p>
<p>However, I think using a template with a Razor script on it seems a bit more powerful. As I've shown above, it's easy to work within the context of a page using &nbsp;altTemplates, but you can also still write any old class that returns a string (or XML) and call that from Razor. In fact, I could just call my existing /base extension from the Razor file because, as you should know, from Razor you can access any old class in your solution.&nbsp;</p>
<p>What I do see happening is that people will write @functions in Razor and never extract them into a seperate method. This is great for quick prototyping and if you really are never going to use those functions again, it's no problem. But it does make it a bit easier to start ignoring seperation of concerns and the DRY (don't repeat yourself) rule and just start copying functions from one Razor script into the other.</p>
<p>All I can say is: with great power comes great responsibility. If you want to be able to change your code in few months, make sure to <a href="http://www.codinghorror.comhttps://cultiv.nl/blog/2004/10/a-pragmatic-quick-reference.html"> refactor early and refactor often&nbsp;(#47)</a>.</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>A few months ago I posted about <a href="https://cultiv.nl/blog/using-base-to-create-and-consume-a-json-string/" title="Using &quot;/base&quot; to create and consume a JSON string"> outputting javascript objects (Json) using an umbraco's "/base"</a>. As you might've noticed, I've been becoming a fan of using Razor in Umbraco and had a bit of an epiphany the other day: why not use Razor to create my Json strings!</p>
<p>So, to do this, I created a new template, let's call it "RazorJson" and add a new macro on it:</p>
<pre class="brush: xml">&lt;umbraco:Macro FileLocation="~/macroScripts/give-me-json.cshtml" runat="server" /&gt;
</pre>
<p>It's important to remember that, in Umbraco, you don't have to create a new page that actually uses this template, if there's no URL conflicts (a node in the root of the site is not called RazorJson), then you can call a template directly. <em>Do note that that context in this case will be the home page (more on that later).</em>&nbsp;</p>
<p>By going to http://mysite.com/RazorJson I get to see my newly created template, but because it is still empty at the moment I get a blank screen.&nbsp;</p>
<p>Let's say that I want to output the current node's properties in Json, we can just do something very simple like this:</p>
<pre class="brush: c-sharp">@{
var node = new umbraco.NodeFactory.Node(Model.Id);
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
}<br />
@Html.Raw(serializer.Serialize(node.Properties))
</pre>
<p>So we're taking the current node's Id (Model.Id) and instantiate a new Node() from it. Then it's properties gets serialized into a Json string and that is what's being shown on the page.&nbsp;</p>
<p>Presto!</p>
<p><img src="https://cultiv.nl/media/5119/2011-07-25_104816_498x235.jpg" alt="2011-07-25_104816" width="498" height="235" /></p>
<p>Now, to make it a bit more interesting, remember how I said this page would only run in the home page's context? You could just turn any of your pages into a Json object by going to, for example, http://mysite.com/about?altTemplate=RazorJson<br /> This will render the "about" page with the RazorJson template and therefore output all of the "about" page's properties in Json notation.</p>
<p>I tweeted about this and got some comments, among which this one:</p>
<p><a href="http://twitter.com/#!/agrath/status/94346353345441792"><img src="https://cultiv.nl/media/5080/2011-07-25_102146_499x265.jpg" alt="2011-07-25_102146" width="499" height="265" /></a></p>
<p>Gareth is right, to create a /base extension, you write a seperate class that handles your businesslogic for you and /base just outputs either XML or a string.</p>
<p>However, I think using a template with a Razor script on it seems a bit more powerful. As I've shown above, it's easy to work within the context of a page using &nbsp;altTemplates, but you can also still write any old class that returns a string (or XML) and call that from Razor. In fact, I could just call my existing /base extension from the Razor file because, as you should know, from Razor you can access any old class in your solution.&nbsp;</p>
<p>What I do see happening is that people will write @functions in Razor and never extract them into a seperate method. This is great for quick prototyping and if you really are never going to use those functions again, it's no problem. But it does make it a bit easier to start ignoring seperation of concerns and the DRY (don't repeat yourself) rule and just start copying functions from one Razor script into the other.</p>
<p>All I can say is: with great power comes great responsibility. If you want to be able to change your code in few months, make sure to <a href="http://www.codinghorror.comhttps://cultiv.nl/blog/2004/10/a-pragmatic-quick-reference.html"> refactor early and refactor often&nbsp;(#47)</a>.</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>How to install Umbraco manually</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/how-to-install-umbraco-manually/</link>
                <pubDate>Mon, 18 Jul 2011 17:28:05 GMT</pubDate>
                <guid>https://cultiv.nl/blog/how-to-install-umbraco-manually/</guid>
                <description>
                    <![CDATA[<p>I've installed Umbraco a million times, so I know how it works. But sometimes people get frustrated when they're starting with Umbraco for the first time.</p>
<p><a href="http://twitter.com/bradykelly/statuses/92975656975089664"><img src="https://cultiv.nl/media/4929/2011-07-18_172955_500x225.jpg" alt="2011-07-18_172955" width="500" height="225" /></a></p>
<p>Sorry XP users, this is written for Windows 7 (you really need to update your 11 year old OS, really). Also, please remember that there's a thousand different computer configurations out there, so this might not be entirely accurate for your specific computer.</p>
<p>So here's a step-by-step guide. This is most certainly not the easiest way of installing Umbraco, but it gives you and overview of how you can do it completely manually, without tools like the Web Platform Installer or <a href="http://www.microsoft.com/web/post/installing-umbraco-with-webmatrix"> Webmatrix</a>.</p>
<p>Let's get started:</p>
<ol>
<li>Download the latest <a href="http://umbraco.codeplex.com/releases/">Umbraco release</a>&nbsp;(choose the <strong>umbraco binaries</strong>, <em>please don't try to install from the source, if you're a new user you really don't need to touch the source for months at least</em>)<br /> <img src="https://cultiv.nl/media/5053/umbraco-codeplex-download_496x235.jpg" alt="Umbraco -codeplex -download" width="496" height="235" />&nbsp;</li>
<li>Unzip the files into the directory in which you want to install Umbraco. In this example I will do it in: <strong>D:\Dev\MyNewUmbracoSite</strong><br /> <em>Note: Before you unzip the umbraco binaries, right-click the zip file and choose "Properties", then hit the "Unblock" button to make sure none of the dll's will be blocked. I use <a href="http://www.7-zip.org/">7zip</a> in which you don't have to do this.<br /> <img src="https://cultiv.nl/media/4950/2011-07-18_182642.gif" alt="2011-07-18_182642" width="367" height="505" />&nbsp;</em></li>
<li>Here we're going to do ourselves a huge favor by <strong>not installing Umbraco in a virtual directory</strong>.&nbsp;<br /> In my hosts file, I now add a new domain name, that I want to use for my site, in my case: <strong>mynewumbracosite.local<br /> </strong> The hosts file can be found in: <em>C:\Windows\System32\drivers\etc<br /> Make sure that the current windows user has permissions to the hosts file, as of Windows 7 this file is not writable by default.<br /> <img src="https://cultiv.nl/media/4959/2011-07-18_182807.gif" alt="2011-07-18_182807" width="367" height="446" /><br /> </em><br /> Add the entry:<em><br /> </em> 127.0.0.1 &nbsp; &nbsp; &nbsp;mynewumbracosite.local<br /> <br /> <img src="https://cultiv.nl/media/4965/2011-07-18_182841_500x354.jpg" alt="2011-07-18_182841" width="500" height="354" /><br /> When that is done, the site can be created in IIS.</li>
<li>Start your IIS Manager and right click on "Sites" and choose "Add web site".&nbsp;</li>
<li>The site name will be&nbsp;<strong>MyNewUmbracoSite</strong>, the Physical path will be&nbsp;<strong>D:\Dev\MyNewUmbracoSite</strong> and the Host name is:&nbsp;<strong>mynewumbracosite.local<br /> </strong> The application pool should be changed to use the ASP.NET v4.0 app pool.&nbsp;<br /> <em>Note: the application pool should be configured to use integrated pipeline mode (this is the default for the ASP.NET v.4.0 app pool).<br /> <img src="https://cultiv.nl/media/4974/2011-07-18_183029_499x485.jpg" alt="2011-07-18_183029" width="499" height="485" />&nbsp;</em></li>
<li>Next, you should set some permissions so that IIS is able to execute the pages in your site, right-click on the MyNewUmbracoSite folder in D:\Dev, choose Properties and go to Security. Then click the Edit button and the Add button. Find the IIS_IUSRS account and give is Full Control permissions.<br /> <img src="https://cultiv.nl/media/4983/2011-07-18_183216.gif" alt="2011-07-18_183216" width="367" height="446" /><br /> Make sure to read&nbsp; <a href="http://our.umbraco.org/wiki/reference/files-and-folders/permissions"> more information about setting permissions</a>&nbsp;as just giving full control everywhere is not best practice.</li>
<li>Alright, almost ready to start the install process, go into your SQL Server management studio and create a new database (for example: <strong>mynewumbracosite</strong>).<br /> <img src="https://cultiv.nl/media/4989/2011-07-18_183332_500x449.jpg" alt="2011-07-18_183332" width="500" height="449" /></li>
<li>In the Security\Logins section of Management Studio, create a new user (SQL Server authentication, remember to uncheck "Enforce password policy").<br /> <img src="https://cultiv.nl/media/4995/2011-07-18_183446.gif" alt="2011-07-18_183446" width="283" height="199" /><br /> <img src="https://cultiv.nl/media/5001/2011-07-18_183510_500x449.jpg" alt="2011-07-18_183510" width="500" height="449" /><br /> Remember the credentials, mine will be <strong>umbraco</strong> / <strong>password</strong></li>
<li>Go back into your database and go to Security\Users.&nbsp;<br /> <img src="https://cultiv.nl/media/5007/2011-07-18_183632.gif" alt="2011-07-18_183632" width="204" height="255" /><br /> Enter the username <em>umbraco</em> in both user name and login name fields. Enter <em>dbo</em> in the default schema field and make the user <em>db_owner</em> for schemas and roles.<br /> <img src="https://cultiv.nl/media/5013/2011-07-18_183710_500x449.jpg" alt="2011-07-18_183710" width="500" height="449" /></li>
<li>Now you can go to http://mynewumbracosite.local/ and you should be presented with the setup screen.</li>
<li>Go through the wizard and when asked for a database, choose "I already have a blank SQL Server or MySQL database" and then "Microsoft SQL Server".</li>
<li>Enter the server name, database name and credential that you just made and click "Install".<br /> <img src="https://cultiv.nl/media/5022/2011-07-18_183812.gif" alt="2011-07-18_183812" width="478" height="480" /></li>
<li>As prompted by the installer, create a new user for your umbraco login.<br /> <img src="https://cultiv.nl/media/5028/2011-07-18_183937_500x378.jpg" alt="2011-07-18_183937" width="500" height="378" /></li>
<li>For the next step in the install wizard, if you want install a starter kit do so, if not choose not to.</li>
<li>When you hit <strong>next</strong>, you're <strong>done</strong>.</li>
</ol>
<p><br /> Please leave a comment when there's something unclear. If you follow along and do things exactly like in this guide, you should be good to go.</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>I've installed Umbraco a million times, so I know how it works. But sometimes people get frustrated when they're starting with Umbraco for the first time.</p>
<p><a href="http://twitter.com/bradykelly/statuses/92975656975089664"><img src="https://cultiv.nl/media/4929/2011-07-18_172955_500x225.jpg" alt="2011-07-18_172955" width="500" height="225" /></a></p>
<p>Sorry XP users, this is written for Windows 7 (you really need to update your 11 year old OS, really). Also, please remember that there's a thousand different computer configurations out there, so this might not be entirely accurate for your specific computer.</p>
<p>So here's a step-by-step guide. This is most certainly not the easiest way of installing Umbraco, but it gives you and overview of how you can do it completely manually, without tools like the Web Platform Installer or <a href="http://www.microsoft.com/web/post/installing-umbraco-with-webmatrix"> Webmatrix</a>.</p>
<p>Let's get started:</p>
<ol>
<li>Download the latest <a href="http://umbraco.codeplex.com/releases/">Umbraco release</a>&nbsp;(choose the <strong>umbraco binaries</strong>, <em>please don't try to install from the source, if you're a new user you really don't need to touch the source for months at least</em>)<br /> <img src="https://cultiv.nl/media/5053/umbraco-codeplex-download_496x235.jpg" alt="Umbraco -codeplex -download" width="496" height="235" />&nbsp;</li>
<li>Unzip the files into the directory in which you want to install Umbraco. In this example I will do it in: <strong>D:\Dev\MyNewUmbracoSite</strong><br /> <em>Note: Before you unzip the umbraco binaries, right-click the zip file and choose "Properties", then hit the "Unblock" button to make sure none of the dll's will be blocked. I use <a href="http://www.7-zip.org/">7zip</a> in which you don't have to do this.<br /> <img src="https://cultiv.nl/media/4950/2011-07-18_182642.gif" alt="2011-07-18_182642" width="367" height="505" />&nbsp;</em></li>
<li>Here we're going to do ourselves a huge favor by <strong>not installing Umbraco in a virtual directory</strong>.&nbsp;<br /> In my hosts file, I now add a new domain name, that I want to use for my site, in my case: <strong>mynewumbracosite.local<br /> </strong> The hosts file can be found in: <em>C:\Windows\System32\drivers\etc<br /> Make sure that the current windows user has permissions to the hosts file, as of Windows 7 this file is not writable by default.<br /> <img src="https://cultiv.nl/media/4959/2011-07-18_182807.gif" alt="2011-07-18_182807" width="367" height="446" /><br /> </em><br /> Add the entry:<em><br /> </em> 127.0.0.1 &nbsp; &nbsp; &nbsp;mynewumbracosite.local<br /> <br /> <img src="https://cultiv.nl/media/4965/2011-07-18_182841_500x354.jpg" alt="2011-07-18_182841" width="500" height="354" /><br /> When that is done, the site can be created in IIS.</li>
<li>Start your IIS Manager and right click on "Sites" and choose "Add web site".&nbsp;</li>
<li>The site name will be&nbsp;<strong>MyNewUmbracoSite</strong>, the Physical path will be&nbsp;<strong>D:\Dev\MyNewUmbracoSite</strong> and the Host name is:&nbsp;<strong>mynewumbracosite.local<br /> </strong> The application pool should be changed to use the ASP.NET v4.0 app pool.&nbsp;<br /> <em>Note: the application pool should be configured to use integrated pipeline mode (this is the default for the ASP.NET v.4.0 app pool).<br /> <img src="https://cultiv.nl/media/4974/2011-07-18_183029_499x485.jpg" alt="2011-07-18_183029" width="499" height="485" />&nbsp;</em></li>
<li>Next, you should set some permissions so that IIS is able to execute the pages in your site, right-click on the MyNewUmbracoSite folder in D:\Dev, choose Properties and go to Security. Then click the Edit button and the Add button. Find the IIS_IUSRS account and give is Full Control permissions.<br /> <img src="https://cultiv.nl/media/4983/2011-07-18_183216.gif" alt="2011-07-18_183216" width="367" height="446" /><br /> Make sure to read&nbsp; <a href="http://our.umbraco.org/wiki/reference/files-and-folders/permissions"> more information about setting permissions</a>&nbsp;as just giving full control everywhere is not best practice.</li>
<li>Alright, almost ready to start the install process, go into your SQL Server management studio and create a new database (for example: <strong>mynewumbracosite</strong>).<br /> <img src="https://cultiv.nl/media/4989/2011-07-18_183332_500x449.jpg" alt="2011-07-18_183332" width="500" height="449" /></li>
<li>In the Security\Logins section of Management Studio, create a new user (SQL Server authentication, remember to uncheck "Enforce password policy").<br /> <img src="https://cultiv.nl/media/4995/2011-07-18_183446.gif" alt="2011-07-18_183446" width="283" height="199" /><br /> <img src="https://cultiv.nl/media/5001/2011-07-18_183510_500x449.jpg" alt="2011-07-18_183510" width="500" height="449" /><br /> Remember the credentials, mine will be <strong>umbraco</strong> / <strong>password</strong></li>
<li>Go back into your database and go to Security\Users.&nbsp;<br /> <img src="https://cultiv.nl/media/5007/2011-07-18_183632.gif" alt="2011-07-18_183632" width="204" height="255" /><br /> Enter the username <em>umbraco</em> in both user name and login name fields. Enter <em>dbo</em> in the default schema field and make the user <em>db_owner</em> for schemas and roles.<br /> <img src="https://cultiv.nl/media/5013/2011-07-18_183710_500x449.jpg" alt="2011-07-18_183710" width="500" height="449" /></li>
<li>Now you can go to http://mynewumbracosite.local/ and you should be presented with the setup screen.</li>
<li>Go through the wizard and when asked for a database, choose "I already have a blank SQL Server or MySQL database" and then "Microsoft SQL Server".</li>
<li>Enter the server name, database name and credential that you just made and click "Install".<br /> <img src="https://cultiv.nl/media/5022/2011-07-18_183812.gif" alt="2011-07-18_183812" width="478" height="480" /></li>
<li>As prompted by the installer, create a new user for your umbraco login.<br /> <img src="https://cultiv.nl/media/5028/2011-07-18_183937_500x378.jpg" alt="2011-07-18_183937" width="500" height="378" /></li>
<li>For the next step in the install wizard, if you want install a starter kit do so, if not choose not to.</li>
<li>When you hit <strong>next</strong>, you're <strong>done</strong>.</li>
</ol>
<p><br /> Please leave a comment when there's something unclear. If you follow along and do things exactly like in this guide, you should be good to go.</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Umbraco developer productivity with uSiteBuilder</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/umbraco-developer-productivity-with-usitebuilder/</link>
                <pubDate>Mon, 09 May 2011 08:30:34 GMT</pubDate>
                <guid>https://cultiv.nl/blog/umbraco-developer-productivity-with-usitebuilder/</guid>
                <description>
                    <![CDATA[<p>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..</p>
<p>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 <a href="http://www.vegaitsourcing.rs/">Vega IT Sourcing</a> must have felt the same way and developed a solution for this called <a href="http://usitebuilder.vegaitsourcing.rs/">uSiteBuilder</a>.&nbsp;</p>
<p>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 <a href="http://usitebuilder.codeplex.com/SourceControl/list/changesets"> the source of uSiteBuilder</a> and from the "Vega.USiteBuilder\bin\Debug" folder I took the&nbsp;Vega.USiteBuilder.dll to use in my project.</p>
<p>My default Umbraco solution looks a bit like this:</p>
<p><img src="https://cultiv.nl/media/4570/umbracosolution.png" alt="Umbracosolution" width="215" height="649" /></p>
<p>More on how I set this up can be found in the <a href="https://cultiv.nl/blog/easily-debug-your-custom-umbraco-user-controls-in-visual-studio/" title="Easily debug your custom Umbraco user controls in Visual Studio"> Easily debug your custom Umbraco user controls in Visual Studio blog post</a>. 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.</p>
<p>I reference the uSiteBuilder dll in the "SomeCompany.Extensions" project and then I'm ready to get started.</p>
<p>My post-build events look like this by the way:</p>
<pre class="brush: xml">XCOPY "$(ProjectDir)bin\SomeCompany.*" "$(ProjectDir)..\Umbraco\bin\" /y<br />
XCOPY "$(ProjectDir)UserControls\*.ascx" "$(ProjectDir)..\Umbraco\UserControls\" /y<br />
XCOPY "$(ProjectDir)Masterpages\*.master" "$(ProjectDir)..\Umbraco\masterpages\" /d /y
</pre>
<p>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.</p>
<p><strong>Master pages</strong></p>
<p>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.</p>
<p>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.</p>
<pre class="brush: xml">&lt;%@ Master Language="C#" AutoEventWireup="true"<br />
CodeBehind="Main.master.cs"<br />
Inherits="SomeCompany.Extensions.MasterPages.Main"<br />
MasterPageFile="~/umbraco/masterpages/default.master" %&gt;
</pre>
<p>We'll get back to this Masterpage later.</p>
<p><strong>Document Types</strong></p>
<p>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!</p>
<p>As you <a href="https://cultiv.nl/blog/tip-of-the-week-the-ultimate-site-structure-setup/" title="Tip of the week: The &quot;ultimate&quot; site structure setup"> might have read</a>, I set up all of my sites using a SiteSettings node first and everything else goes under that.&nbsp;My goal is to get a document type structure that looks like this:</p>
<p><img src="https://cultiv.nl/media/4579/documenttypes.png" alt="Documenttypes" width="142" height="79" /></p>
<p>So let's get started with some code in DocumentTypes\SiteSettings.cs:</p>
<pre class="brush: c-sharp">using Vega.USiteBuilder;<br />
<br />
namespace SomeCompany.Extensions.DocumentTypes<br />
{<br />
[DocumentType(Name = "Site Settings", IconUrl = "house.png", Thumbnail = "developer.png", AllowedChildNodeTypes = new[] { typeof(TextPage) })]<br />
public class SiteSettings : DocumentTypeBase<br />
{<br />
[DocumentTypeProperty(UmbracoPropertyType.ContentPicker, Name = "Homepage", Tab = "Settings", Description = "The item that you pick here will be the homepage of your site.")]<br />
public string umbracoInternalRedirectId { get; set; }<br />
<br />
[DocumentTypeProperty(UmbracoPropertyType.TextboxMultiple, Name = "Google Analytics Code", Tab = "Settings", Description = "Paste your Google Analytics code here to get statistics of your website")]<br />
public string googleAnalyticsCode { get; set; }<br />
}<br />
}
</pre>
<p>Make sure to go through the&nbsp;<a href="http://usitebuilder.vegaitsourcing.rs/tutorials">uSiteBuilder tutorials</a>&nbsp;if you're not sure what's actually going on here.</p>
<p>Great, that's that sorted, we can continue to the PageSettings document type:</p>
<pre class="brush: c-sharp">using Vega.USiteBuilder;<br />
<br />
namespace SomeCompany.Extensions.DocumentTypes<br />
{<br />
[DocumentType(Name = "Page Settings", IconUrl = "folder.gif", Thumbnail = "folder.png", AllowedChildNodeTypes = new[] { typeof(TextPage) })]<br />
public class PageSettings : DocumentTypeBase<br />
{<br />
[DocumentTypeProperty(UmbracoPropertyType.Textstring, Name = "Page title", Tab = "Page settings")]<br />
public string pageTitle { get; set; }<br />
<br />
[DocumentTypeProperty(UmbracoPropertyType.Textstring, Name = "Meta title", Tab = "Page settings")]<br />
public string metaTitle { get; set; }<br />
<br />
[DocumentTypeProperty(UmbracoPropertyType.Textstring, Name = "Meta description", Tab = "Page settings")]<br />
public string metaDescription { get; set; }<br />
<br />
[DocumentTypeProperty(UmbracoPropertyType.TrueFalse, Name = "Hide in navigation?", Tab = "Navigation")]<br />
public string umbracoNaviHide { get; set; }<br />
}<br />
}
</pre>
<p>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.</p>
<p>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:&nbsp;</p>
<pre class="brush: c-sharp">using Vega.USiteBuilder;<br />
<br />
namespace SomeCompany.Extensions.DocumentTypes<br />
{<br />
[DocumentType(Name = "Text page", IconUrl = "page.png", Thumbnail = "docWithImage.png", AllowedTemplates = new [] { "TextPage" }, DefaultTemplate = typeof (TextPage))]<br />
public class TextPage : PageSettings<br />
{<br />
[DocumentTypeProperty(UmbracoPropertyType.RichtextEditor, Name = "Content", Tab = "Content", Description = "")]<br />
public string bodyText { get; set; }<br />
}<br />
}
</pre>
<p>I am inheriting from the PageSettings class that I've just created so that TextPage will be nested under it.</p>
<p>Also, I have set the AllowedTemplates to TextPage, which doesn't exist yet. So it can now be created.</p>
<p>I've created a ContentPlaceHolder in Main.master:</p>
<pre class="brush: xml">&lt;asp:ContentPlaceHolder Id="body" runat="server"&gt;&lt;/asp:ContentPlaceHolder&gt;
</pre>
<p>Now I need to create the TextPage Masterpage by adding a new nested masterpage, based on Main.master:</p>
<p><span><img src="https://cultiv.nl/media/4585/nestedmaster_497x300.jpg" alt="Nestedmaster" width="497" height="300" /></span></p>
<p><span>We could just copy both masterpages (Main &amp; 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.&nbsp;</span></p>
<p>So, as promised, we're getting back to Main.master. Go into the codebehind and change it to inherit from SiteSettings, like so:</p>
<pre class="brush: c-sharp">public partial class Main : Vega.USiteBuilder.TemplateBase&lt;DocumentTypes.SiteSettings&gt;
</pre>
<p>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:</p>
<pre class="brush: c-sharp">public partial class TextPage : Vega.USiteBuilder.TemplateBase&lt;DocumentTypes.TextPage&gt;
</pre>
<p><strong>What can we not do?</strong></p>
<p>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.</p>
<p>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.</p>
<p>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.</p>
<p>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!</p>
<p><strong>Putting it all together</strong></p>
<p>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.</p>
<p>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" &gt; expanding "Document types" &gt; going to the "Generic properties" tab and finding the alias.</p>
<p>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.</p>
<p>That's right, it's as easy as referring to a file. In your template, just insert a macro like this:</p>
<pre class="brush: xml">&lt;umbraco:Macro FileLocation="~/macroScripts/MainMenu.cshtml" runat="server" /&gt;
</pre>
<p>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.&nbsp;</p>
<p>Thanks to the great folks at <a href="http://www.vegaitsourcing.rs/">Vega IT Sourcing</a> for a truely awesome tool that makes my life much easier, I love it!</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>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..</p>
<p>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 <a href="http://www.vegaitsourcing.rs/">Vega IT Sourcing</a> must have felt the same way and developed a solution for this called <a href="http://usitebuilder.vegaitsourcing.rs/">uSiteBuilder</a>.&nbsp;</p>
<p>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 <a href="http://usitebuilder.codeplex.com/SourceControl/list/changesets"> the source of uSiteBuilder</a> and from the "Vega.USiteBuilder\bin\Debug" folder I took the&nbsp;Vega.USiteBuilder.dll to use in my project.</p>
<p>My default Umbraco solution looks a bit like this:</p>
<p><img src="https://cultiv.nl/media/4570/umbracosolution.png" alt="Umbracosolution" width="215" height="649" /></p>
<p>More on how I set this up can be found in the <a href="https://cultiv.nl/blog/easily-debug-your-custom-umbraco-user-controls-in-visual-studio/" title="Easily debug your custom Umbraco user controls in Visual Studio"> Easily debug your custom Umbraco user controls in Visual Studio blog post</a>. 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.</p>
<p>I reference the uSiteBuilder dll in the "SomeCompany.Extensions" project and then I'm ready to get started.</p>
<p>My post-build events look like this by the way:</p>
<pre class="brush: xml">XCOPY "$(ProjectDir)bin\SomeCompany.*" "$(ProjectDir)..\Umbraco\bin\" /y<br />
XCOPY "$(ProjectDir)UserControls\*.ascx" "$(ProjectDir)..\Umbraco\UserControls\" /y<br />
XCOPY "$(ProjectDir)Masterpages\*.master" "$(ProjectDir)..\Umbraco\masterpages\" /d /y
</pre>
<p>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.</p>
<p><strong>Master pages</strong></p>
<p>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.</p>
<p>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.</p>
<pre class="brush: xml">&lt;%@ Master Language="C#" AutoEventWireup="true"<br />
CodeBehind="Main.master.cs"<br />
Inherits="SomeCompany.Extensions.MasterPages.Main"<br />
MasterPageFile="~/umbraco/masterpages/default.master" %&gt;
</pre>
<p>We'll get back to this Masterpage later.</p>
<p><strong>Document Types</strong></p>
<p>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!</p>
<p>As you <a href="https://cultiv.nl/blog/tip-of-the-week-the-ultimate-site-structure-setup/" title="Tip of the week: The &quot;ultimate&quot; site structure setup"> might have read</a>, I set up all of my sites using a SiteSettings node first and everything else goes under that.&nbsp;My goal is to get a document type structure that looks like this:</p>
<p><img src="https://cultiv.nl/media/4579/documenttypes.png" alt="Documenttypes" width="142" height="79" /></p>
<p>So let's get started with some code in DocumentTypes\SiteSettings.cs:</p>
<pre class="brush: c-sharp">using Vega.USiteBuilder;<br />
<br />
namespace SomeCompany.Extensions.DocumentTypes<br />
{<br />
[DocumentType(Name = "Site Settings", IconUrl = "house.png", Thumbnail = "developer.png", AllowedChildNodeTypes = new[] { typeof(TextPage) })]<br />
public class SiteSettings : DocumentTypeBase<br />
{<br />
[DocumentTypeProperty(UmbracoPropertyType.ContentPicker, Name = "Homepage", Tab = "Settings", Description = "The item that you pick here will be the homepage of your site.")]<br />
public string umbracoInternalRedirectId { get; set; }<br />
<br />
[DocumentTypeProperty(UmbracoPropertyType.TextboxMultiple, Name = "Google Analytics Code", Tab = "Settings", Description = "Paste your Google Analytics code here to get statistics of your website")]<br />
public string googleAnalyticsCode { get; set; }<br />
}<br />
}
</pre>
<p>Make sure to go through the&nbsp;<a href="http://usitebuilder.vegaitsourcing.rs/tutorials">uSiteBuilder tutorials</a>&nbsp;if you're not sure what's actually going on here.</p>
<p>Great, that's that sorted, we can continue to the PageSettings document type:</p>
<pre class="brush: c-sharp">using Vega.USiteBuilder;<br />
<br />
namespace SomeCompany.Extensions.DocumentTypes<br />
{<br />
[DocumentType(Name = "Page Settings", IconUrl = "folder.gif", Thumbnail = "folder.png", AllowedChildNodeTypes = new[] { typeof(TextPage) })]<br />
public class PageSettings : DocumentTypeBase<br />
{<br />
[DocumentTypeProperty(UmbracoPropertyType.Textstring, Name = "Page title", Tab = "Page settings")]<br />
public string pageTitle { get; set; }<br />
<br />
[DocumentTypeProperty(UmbracoPropertyType.Textstring, Name = "Meta title", Tab = "Page settings")]<br />
public string metaTitle { get; set; }<br />
<br />
[DocumentTypeProperty(UmbracoPropertyType.Textstring, Name = "Meta description", Tab = "Page settings")]<br />
public string metaDescription { get; set; }<br />
<br />
[DocumentTypeProperty(UmbracoPropertyType.TrueFalse, Name = "Hide in navigation?", Tab = "Navigation")]<br />
public string umbracoNaviHide { get; set; }<br />
}<br />
}
</pre>
<p>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.</p>
<p>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:&nbsp;</p>
<pre class="brush: c-sharp">using Vega.USiteBuilder;<br />
<br />
namespace SomeCompany.Extensions.DocumentTypes<br />
{<br />
[DocumentType(Name = "Text page", IconUrl = "page.png", Thumbnail = "docWithImage.png", AllowedTemplates = new [] { "TextPage" }, DefaultTemplate = typeof (TextPage))]<br />
public class TextPage : PageSettings<br />
{<br />
[DocumentTypeProperty(UmbracoPropertyType.RichtextEditor, Name = "Content", Tab = "Content", Description = "")]<br />
public string bodyText { get; set; }<br />
}<br />
}
</pre>
<p>I am inheriting from the PageSettings class that I've just created so that TextPage will be nested under it.</p>
<p>Also, I have set the AllowedTemplates to TextPage, which doesn't exist yet. So it can now be created.</p>
<p>I've created a ContentPlaceHolder in Main.master:</p>
<pre class="brush: xml">&lt;asp:ContentPlaceHolder Id="body" runat="server"&gt;&lt;/asp:ContentPlaceHolder&gt;
</pre>
<p>Now I need to create the TextPage Masterpage by adding a new nested masterpage, based on Main.master:</p>
<p><span><img src="https://cultiv.nl/media/4585/nestedmaster_497x300.jpg" alt="Nestedmaster" width="497" height="300" /></span></p>
<p><span>We could just copy both masterpages (Main &amp; 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.&nbsp;</span></p>
<p>So, as promised, we're getting back to Main.master. Go into the codebehind and change it to inherit from SiteSettings, like so:</p>
<pre class="brush: c-sharp">public partial class Main : Vega.USiteBuilder.TemplateBase&lt;DocumentTypes.SiteSettings&gt;
</pre>
<p>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:</p>
<pre class="brush: c-sharp">public partial class TextPage : Vega.USiteBuilder.TemplateBase&lt;DocumentTypes.TextPage&gt;
</pre>
<p><strong>What can we not do?</strong></p>
<p>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.</p>
<p>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.</p>
<p>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.</p>
<p>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!</p>
<p><strong>Putting it all together</strong></p>
<p>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.</p>
<p>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" &gt; expanding "Document types" &gt; going to the "Generic properties" tab and finding the alias.</p>
<p>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.</p>
<p>That's right, it's as easy as referring to a file. In your template, just insert a macro like this:</p>
<pre class="brush: xml">&lt;umbraco:Macro FileLocation="~/macroScripts/MainMenu.cshtml" runat="server" /&gt;
</pre>
<p>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.&nbsp;</p>
<p>Thanks to the great folks at <a href="http://www.vegaitsourcing.rs/">Vega IT Sourcing</a> for a truely awesome tool that makes my life much easier, I love it!</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>How to use Razor in Umbraco - Paging</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/how-to-use-razor-in-umbraco-paging/</link>
                <pubDate>Thu, 17 Feb 2011 17:43:28 GMT</pubDate>
                <guid>https://cultiv.nl/blog/how-to-use-razor-in-umbraco-paging/</guid>
                <description>
                    <![CDATA[<p>In my <a href="https://cultiv.nl/blog/how-to-use-razor-in-umbraco-paging/" title="How to use Razor in Umbraco">previous post</a> I've shown the basics of using Razor. But I also wanted to find out what works better in XSLT versus in Razor. Luckily, my page needed paging. Paging is something relatively simple that requires a bit of logic, not something that is trivial to do in XSLT. In fact, every time I look at the faux-"for loop" required in XSLT to make it work, my head starts spinning.</p>
<p><strong>Disclaimer: The Razor &nbsp;implementation is still very new and changing rapidly, some of this information might already be outdated.</strong></p>
<p>Paging is also something that can be made really generic, making it nicely reusable for any page.</p>
<p>There is two parts to the paging solution, a normal C# class (but in the App_Code folder, so no compilation required!) that takes the amount of items and the items that should be displayed per page and then does some calculations based on the "page" querystring (come to think of it, I should've actually made that an input variable as well).</p>
<p>I admit that this is a bit verbose and I don't actually need some of these fields, but it's nice to have them in case I need to do something wild with them later.</p>
<pre class="brush: c-sharp">using System;<br />
using System.Web;<br />
<br />
public class Paging<br />
{<br />
public int ItemsPerPage { get; set; }<br />
public int CurrentPage { get; set; }<br />
public int PreviousPage { get; set; }<br />
public int NextPage { get; set; }<br />
public double TotalPages { get; set; }<br />
public int Skip { get; set; }<br />
public int Take { get; set; }<br />
<br />
public static Paging GetPages(int itemCount, int itemsPerPage)<br />
{<br />
int page;<br />
int.TryParse(HttpContext.Current.Request.QueryString["page"], out page);<br />
if (page == 0) page = 1;<br />
<br />
var pages = new Paging { ItemsPerPage = itemsPerPage, CurrentPage = page, PreviousPage = page - 1, NextPage = page + 1, TotalPages = Math.Ceiling(itemCount / (Double)itemsPerPage), Skip = (page*itemsPerPage) - itemsPerPage, Take = itemsPerPage };<br />

return pages;<br />
}<br />
}
</pre>
<p>Then, I needed a really basic way to show the paging. I wanted just some links for the different pages and a "previous" and "next" link. Also, the "current" page shouldn't be clickable. So we bring out a Razor helper (also in the App_Code folder) that can be reused and potentially modified when needed.</p>
<pre class="brush: cshtml">@using umbraco;<br />
<br />
@helper RenderPaging(Paging paging, int currentId) {<br />
if (paging.CurrentPage &gt; 1)<br />
{<br />
&lt;a href="@library.NiceUrl(currentId)?page=@paging.PreviousPage"&gt;&lt; Vorige&lt;/a&gt;<br />
}<br />
<br />
for (var i = 1; i &lt;= paging.TotalPages; i++)<br />
{<br />
if (paging.CurrentPage == i)<br />
{<br />
@i&lt;text&gt;&amp;nbsp;&lt;/text&gt;<br />
}<br />
else<br />
{<br />
&lt;a href="@library.NiceUrl(currentId)?page=@i"&gt;@i&lt;/a&gt;&lt;text&gt;&amp;nbsp;&lt;/text&gt;<br />
}<br />
}<br />
<br />
if (paging.CurrentPage &lt; paging.TotalPages)<br />
{<br />
&lt;a href="@library.NiceUrl(currentId)?page=@paging.NextPage"&gt;Volgende &gt;&lt;/a&gt;<br />
}<br />
}
</pre>
<p>That's all, so now in my overviewpage, I initilialize the paging object and select the records that I want to show for the current page. Note that Skip() and Take() have been added to my Linq query so that I only get the 10 articles that I want.</p>
<pre class="brush: cshtml">@{
var paging = Paging.GetPages(allArticles.Count(), 10);&nbsp;<br />
var selectedArticles = allArticles.OrderByDescending(x =&gt; x.CreateDate).Skip(paging.Skip).Take(paging.Take).ToList();
}<br />
&lt;div class="articleList"&gt;<br />
&lt;ul&gt;<br />
@foreach(var article in selectedArticles) {<br />
&lt;li&gt;@article.NodeName&lt;/li&gt;<br />
}<br />
&lt;/ul&gt;
</pre>
<p>And finally, to render the paging, it's a matter of calling the helper, note that the namespace is once again the name of the .cshtml file (as in the functions in the previous post).</p>
<pre class="brush: cshtml">&lt;div class="paging"&gt;<br />
@PagingTemplate.RenderPaging(paging, Current.Id)<br />
&lt;/div&gt;
</pre>
<p>There you go, from 100+ lines of unreadable XSLT to about 60 lines of nice, clean and easily reusable paging in Razor. What's not to love?</p>
<p>Ps. I still love XSLT, really I do. :-)</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>In my <a href="https://cultiv.nl/blog/how-to-use-razor-in-umbraco-paging/" title="How to use Razor in Umbraco">previous post</a> I've shown the basics of using Razor. But I also wanted to find out what works better in XSLT versus in Razor. Luckily, my page needed paging. Paging is something relatively simple that requires a bit of logic, not something that is trivial to do in XSLT. In fact, every time I look at the faux-"for loop" required in XSLT to make it work, my head starts spinning.</p>
<p><strong>Disclaimer: The Razor &nbsp;implementation is still very new and changing rapidly, some of this information might already be outdated.</strong></p>
<p>Paging is also something that can be made really generic, making it nicely reusable for any page.</p>
<p>There is two parts to the paging solution, a normal C# class (but in the App_Code folder, so no compilation required!) that takes the amount of items and the items that should be displayed per page and then does some calculations based on the "page" querystring (come to think of it, I should've actually made that an input variable as well).</p>
<p>I admit that this is a bit verbose and I don't actually need some of these fields, but it's nice to have them in case I need to do something wild with them later.</p>
<pre class="brush: c-sharp">using System;<br />
using System.Web;<br />
<br />
public class Paging<br />
{<br />
public int ItemsPerPage { get; set; }<br />
public int CurrentPage { get; set; }<br />
public int PreviousPage { get; set; }<br />
public int NextPage { get; set; }<br />
public double TotalPages { get; set; }<br />
public int Skip { get; set; }<br />
public int Take { get; set; }<br />
<br />
public static Paging GetPages(int itemCount, int itemsPerPage)<br />
{<br />
int page;<br />
int.TryParse(HttpContext.Current.Request.QueryString["page"], out page);<br />
if (page == 0) page = 1;<br />
<br />
var pages = new Paging { ItemsPerPage = itemsPerPage, CurrentPage = page, PreviousPage = page - 1, NextPage = page + 1, TotalPages = Math.Ceiling(itemCount / (Double)itemsPerPage), Skip = (page*itemsPerPage) - itemsPerPage, Take = itemsPerPage };<br />

return pages;<br />
}<br />
}
</pre>
<p>Then, I needed a really basic way to show the paging. I wanted just some links for the different pages and a "previous" and "next" link. Also, the "current" page shouldn't be clickable. So we bring out a Razor helper (also in the App_Code folder) that can be reused and potentially modified when needed.</p>
<pre class="brush: cshtml">@using umbraco;<br />
<br />
@helper RenderPaging(Paging paging, int currentId) {<br />
if (paging.CurrentPage &gt; 1)<br />
{<br />
&lt;a href="@library.NiceUrl(currentId)?page=@paging.PreviousPage"&gt;&lt; Vorige&lt;/a&gt;<br />
}<br />
<br />
for (var i = 1; i &lt;= paging.TotalPages; i++)<br />
{<br />
if (paging.CurrentPage == i)<br />
{<br />
@i&lt;text&gt;&amp;nbsp;&lt;/text&gt;<br />
}<br />
else<br />
{<br />
&lt;a href="@library.NiceUrl(currentId)?page=@i"&gt;@i&lt;/a&gt;&lt;text&gt;&amp;nbsp;&lt;/text&gt;<br />
}<br />
}<br />
<br />
if (paging.CurrentPage &lt; paging.TotalPages)<br />
{<br />
&lt;a href="@library.NiceUrl(currentId)?page=@paging.NextPage"&gt;Volgende &gt;&lt;/a&gt;<br />
}<br />
}
</pre>
<p>That's all, so now in my overviewpage, I initilialize the paging object and select the records that I want to show for the current page. Note that Skip() and Take() have been added to my Linq query so that I only get the 10 articles that I want.</p>
<pre class="brush: cshtml">@{
var paging = Paging.GetPages(allArticles.Count(), 10);&nbsp;<br />
var selectedArticles = allArticles.OrderByDescending(x =&gt; x.CreateDate).Skip(paging.Skip).Take(paging.Take).ToList();
}<br />
&lt;div class="articleList"&gt;<br />
&lt;ul&gt;<br />
@foreach(var article in selectedArticles) {<br />
&lt;li&gt;@article.NodeName&lt;/li&gt;<br />
}<br />
&lt;/ul&gt;
</pre>
<p>And finally, to render the paging, it's a matter of calling the helper, note that the namespace is once again the name of the .cshtml file (as in the functions in the previous post).</p>
<pre class="brush: cshtml">&lt;div class="paging"&gt;<br />
@PagingTemplate.RenderPaging(paging, Current.Id)<br />
&lt;/div&gt;
</pre>
<p>There you go, from 100+ lines of unreadable XSLT to about 60 lines of nice, clean and easily reusable paging in Razor. What's not to love?</p>
<p>Ps. I still love XSLT, really I do. :-)</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>How to use Razor in Umbraco</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/how-to-use-razor-in-umbraco/</link>
                <pubDate>Wed, 16 Feb 2011 12:02:01 GMT</pubDate>
                <guid>https://cultiv.nl/blog/how-to-use-razor-in-umbraco/</guid>
                <description>
                    <![CDATA[<p>This article is about the upcoming version of Umbraco (4.6.2), that uses normal .cshtml files instead of the .razor file extension. Examples will also be presented in HTML 5 format, so do remember that the tags are part of HTML 5, not Razor.</p>
<p><strong>Disclaimer: The Razor &nbsp;implementation is still very new and changing rapidly, some of this information might already be outdated.</strong></p>
<p>When using the Razor view engine it's important to remember that you are just writing HTML and, when you need some data, you switch context by starting with the "@" sign and adding some C# (yes, you can also make .vbhtml files and start writing VB, if you must):</p>
<pre class="brush: xml">&lt;article&gt;<br />
&lt;header&gt;&lt;h2&gt;@Model.Name&lt;/h2&gt;&lt;/header&gt;<br />
&lt;img src="@Model.ImageUpload" alt="@Model.Name" /&gt;<br />
@(Html.Raw(Model.BodyText))<br />
&lt;/article&gt;
</pre>
<p>In umbraco's case, the "Current" object holds the same data as the "currentPage" variable does in XSLT. All of the properties that are on the current document type are available to you, although you only get intellisense with the default properties (Id, Name, CreateDate, etc.).</p>
<p>As you can see, there's an interesting mix of html and @ signs. Not much to explain here except for the Html.Raw call, this is the same as saying disable-output-escaping="true" in XSLT. If you don't do this, all of the text will be encoded as HTML entities.</p>
<p>Now we have pretty decent looking page, let's make it a little more complex. Say I have a few news articles somewhere in my site, the titles of which I would like to display in a sidebar at all times. I could go and look for those nodes by looking at the Model.Parent and up and up until I was at level 1 and then find the child node with the "Article" type, but that's quite a bit of work to do every time I need to do something similar*.</p>
<p>It was much easier just to use Linq 2 Umbraco and query Umbraco's cached content (I'm open to suggestions if there's a better way).</p>
<p><em>* Although <a href="https://bitbucket.org/ElijahGlover/umbraco.uql/wiki/Home">UQL</a> will make this a bit easier</em></p>
<p>So now I get a Razor template that looks like this:</p>
<pre class="brush: xml">@using System;<br />
@using System.Linq;<br />
@using umbraco;<br />
<br />
@{<br />
var context = new MyNamespace.MyModelDataContext();<br />
var catArticles = context.Articles.OrderByDescending(x =&gt; x.CreateDate).ToList();<br />
}<br />
&lt;article&gt;<br />
&lt;header&gt;&lt;h2&gt;@Model.Name&lt;/h2&gt;&lt;/header&gt;<br />
&lt;img src="@Model.ImageUpload" alt="@Model.Name" /&gt;<br />
@(Html.Raw(Model.BodyText))<br />
&lt;/article&gt;<br />
&lt;aside&gt;<br />
&lt;ul&gt;<br />
@foreach (var article in catArticles)<br />
{<br />
&lt;li&gt;<br />
&lt;a href="@library.NiceUrl(article.Id)"&gt;@article.NodeName&lt;/a&gt;<br />
&lt;li&gt;<br />
}<br />
&lt;/ul&gt;<br />
&lt;/aside&gt;
</pre>
<p>Still pretty easy, now it's time for a real challenge. I have an image upload field and an image cropper on the article pages. The image cropper stores bits of XML for the values of the different crops. So just doing a @article.ImageCrop won't work. Here's where helpers come in.<br /> Helpers can be created inline, but it's better when you just create a new .cshtml file in your App_Code and refer to that helper. It becomes reusable and actually helps you write better modular code. In this case the helper will return a value so it's called a function.</p>
<p>Careful here: if you add a .cshtml file to the App_Code folder through the Visual Studio interface, it will also add a key in the web.config:</p>
<pre class="brush: xml">&lt;add key="webpages:Enabled" value="true" /&gt;
</pre>
<p>This wil result in a "yellow screen of death", complaining that the UmbracoMembershipProvider is configured incorrectly: "Parser Error Message: This method cannot be called during the application's pre-start initialization stage."</p>
<p>So I've created <a href="https://cultiv.nl/media/XmlFunctions.txt">a tiny little XML parser</a> (untested in the real world, be sure to rename from .txt to .cshtml) and will use that to get the cropped image out:</p>
<pre class="brush: xml">&lt;aside&gt;<br />
&lt;ul&gt;<br />
@foreach (var article in catArticles)<br />
{<br />
&lt;li&gt;<br />
&lt;a href="@library.NiceUrl(article.Id)"&gt;<br />
&lt;img src="@XmlFunctions.GetAttributeValue(article.ImageCrop), "/crops/crop[@name = 'Small']", "url")" alt="@article.NodeName" /&gt;<br />
&lt;/a&gt;<br />
&lt;li&gt;<br />
}<br />
&lt;/ul&gt;<br />
&lt;/aside&gt;
</pre>
<p>Note that the namespace of the helper is the filename I've created in the App_Code folder, so XmlFunctions.cshtml translates to the XmlFunctions namespace in the Razor template.</p>
<p>And that concludes the first part of a few Razor posts.</p>
<p>For more info, be sure to check out these links:</p>
<ul>
<li><a href="http://www.aaron-powell.com/umbraco-4-and-razor" target="_blank">http://www.aaron-powell.com/umbraco-4-and-razor</a></li>
<li><a href="http://www.asp.net/webmatrix/tutorials/2-introduction-to-asp-net-web-programming-using-the-razor-syntax" target="_blank">http://www.asp.net/webmatrix/tutorials/2-introduction-to-asp-net-web-programming-using-the-razor-syntax</a></li>
<li><a href="http://weblogs.asp.net/scottgu/archive/2010/07/02/introducing-razor.aspx" target="_blank">http://weblogs.asp.net/scottgu/archive/2010/07/02/introducing-razor.aspx</a></li>
<li><a href="http://joeriks.wordpress.com/2011/01/12/razor-inline-helpers-in-umbraco-juno-full-sitemap-sample/" target="_blank">http://joeriks.wordpress.com/2011/01/12/razor-inline-helpers-in-umbraco-juno-full-sitemap-sample/</a></li>
<li><a href="http://joeriks.wordpress.com/2011/01/04/playing-with-razor-in-umbraco-an-old-skool-contact-form/" target="_blank">http://joeriks.wordpress.com/2011/01/04/playing-with-razor-in-umbraco-an-old-skool-contact-form/</a></li>
<li><a href="http://haacked.com/archive/2011/01/06/razor-syntax-quick-reference.aspx"> http://haacked.com/archive/2011/01/06/razor-syntax-quick-reference.aspx</a></li>
</ul>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>This article is about the upcoming version of Umbraco (4.6.2), that uses normal .cshtml files instead of the .razor file extension. Examples will also be presented in HTML 5 format, so do remember that the tags are part of HTML 5, not Razor.</p>
<p><strong>Disclaimer: The Razor &nbsp;implementation is still very new and changing rapidly, some of this information might already be outdated.</strong></p>
<p>When using the Razor view engine it's important to remember that you are just writing HTML and, when you need some data, you switch context by starting with the "@" sign and adding some C# (yes, you can also make .vbhtml files and start writing VB, if you must):</p>
<pre class="brush: xml">&lt;article&gt;<br />
&lt;header&gt;&lt;h2&gt;@Model.Name&lt;/h2&gt;&lt;/header&gt;<br />
&lt;img src="@Model.ImageUpload" alt="@Model.Name" /&gt;<br />
@(Html.Raw(Model.BodyText))<br />
&lt;/article&gt;
</pre>
<p>In umbraco's case, the "Current" object holds the same data as the "currentPage" variable does in XSLT. All of the properties that are on the current document type are available to you, although you only get intellisense with the default properties (Id, Name, CreateDate, etc.).</p>
<p>As you can see, there's an interesting mix of html and @ signs. Not much to explain here except for the Html.Raw call, this is the same as saying disable-output-escaping="true" in XSLT. If you don't do this, all of the text will be encoded as HTML entities.</p>
<p>Now we have pretty decent looking page, let's make it a little more complex. Say I have a few news articles somewhere in my site, the titles of which I would like to display in a sidebar at all times. I could go and look for those nodes by looking at the Model.Parent and up and up until I was at level 1 and then find the child node with the "Article" type, but that's quite a bit of work to do every time I need to do something similar*.</p>
<p>It was much easier just to use Linq 2 Umbraco and query Umbraco's cached content (I'm open to suggestions if there's a better way).</p>
<p><em>* Although <a href="https://bitbucket.org/ElijahGlover/umbraco.uql/wiki/Home">UQL</a> will make this a bit easier</em></p>
<p>So now I get a Razor template that looks like this:</p>
<pre class="brush: xml">@using System;<br />
@using System.Linq;<br />
@using umbraco;<br />
<br />
@{<br />
var context = new MyNamespace.MyModelDataContext();<br />
var catArticles = context.Articles.OrderByDescending(x =&gt; x.CreateDate).ToList();<br />
}<br />
&lt;article&gt;<br />
&lt;header&gt;&lt;h2&gt;@Model.Name&lt;/h2&gt;&lt;/header&gt;<br />
&lt;img src="@Model.ImageUpload" alt="@Model.Name" /&gt;<br />
@(Html.Raw(Model.BodyText))<br />
&lt;/article&gt;<br />
&lt;aside&gt;<br />
&lt;ul&gt;<br />
@foreach (var article in catArticles)<br />
{<br />
&lt;li&gt;<br />
&lt;a href="@library.NiceUrl(article.Id)"&gt;@article.NodeName&lt;/a&gt;<br />
&lt;li&gt;<br />
}<br />
&lt;/ul&gt;<br />
&lt;/aside&gt;
</pre>
<p>Still pretty easy, now it's time for a real challenge. I have an image upload field and an image cropper on the article pages. The image cropper stores bits of XML for the values of the different crops. So just doing a @article.ImageCrop won't work. Here's where helpers come in.<br /> Helpers can be created inline, but it's better when you just create a new .cshtml file in your App_Code and refer to that helper. It becomes reusable and actually helps you write better modular code. In this case the helper will return a value so it's called a function.</p>
<p>Careful here: if you add a .cshtml file to the App_Code folder through the Visual Studio interface, it will also add a key in the web.config:</p>
<pre class="brush: xml">&lt;add key="webpages:Enabled" value="true" /&gt;
</pre>
<p>This wil result in a "yellow screen of death", complaining that the UmbracoMembershipProvider is configured incorrectly: "Parser Error Message: This method cannot be called during the application's pre-start initialization stage."</p>
<p>So I've created <a href="https://cultiv.nl/media/XmlFunctions.txt">a tiny little XML parser</a> (untested in the real world, be sure to rename from .txt to .cshtml) and will use that to get the cropped image out:</p>
<pre class="brush: xml">&lt;aside&gt;<br />
&lt;ul&gt;<br />
@foreach (var article in catArticles)<br />
{<br />
&lt;li&gt;<br />
&lt;a href="@library.NiceUrl(article.Id)"&gt;<br />
&lt;img src="@XmlFunctions.GetAttributeValue(article.ImageCrop), "/crops/crop[@name = 'Small']", "url")" alt="@article.NodeName" /&gt;<br />
&lt;/a&gt;<br />
&lt;li&gt;<br />
}<br />
&lt;/ul&gt;<br />
&lt;/aside&gt;
</pre>
<p>Note that the namespace of the helper is the filename I've created in the App_Code folder, so XmlFunctions.cshtml translates to the XmlFunctions namespace in the Razor template.</p>
<p>And that concludes the first part of a few Razor posts.</p>
<p>For more info, be sure to check out these links:</p>
<ul>
<li><a href="http://www.aaron-powell.com/umbraco-4-and-razor" target="_blank">http://www.aaron-powell.com/umbraco-4-and-razor</a></li>
<li><a href="http://www.asp.net/webmatrix/tutorials/2-introduction-to-asp-net-web-programming-using-the-razor-syntax" target="_blank">http://www.asp.net/webmatrix/tutorials/2-introduction-to-asp-net-web-programming-using-the-razor-syntax</a></li>
<li><a href="http://weblogs.asp.net/scottgu/archive/2010/07/02/introducing-razor.aspx" target="_blank">http://weblogs.asp.net/scottgu/archive/2010/07/02/introducing-razor.aspx</a></li>
<li><a href="http://joeriks.wordpress.com/2011/01/12/razor-inline-helpers-in-umbraco-juno-full-sitemap-sample/" target="_blank">http://joeriks.wordpress.com/2011/01/12/razor-inline-helpers-in-umbraco-juno-full-sitemap-sample/</a></li>
<li><a href="http://joeriks.wordpress.com/2011/01/04/playing-with-razor-in-umbraco-an-old-skool-contact-form/" target="_blank">http://joeriks.wordpress.com/2011/01/04/playing-with-razor-in-umbraco-an-old-skool-contact-form/</a></li>
<li><a href="http://haacked.com/archive/2011/01/06/razor-syntax-quick-reference.aspx"> http://haacked.com/archive/2011/01/06/razor-syntax-quick-reference.aspx</a></li>
</ul>]]>
                </content:encoded>
            </item>
            <item>
                <title>Tip of the week: The &quot;ultimate&quot; site structure setup</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/tip-of-the-week-the-ultimate-site-structure-setup/</link>
                <pubDate>Sun, 19 Dec 2010 22:26:00 GMT</pubDate>
                <guid>https://cultiv.nl/blog/tip-of-the-week-the-ultimate-site-structure-setup/</guid>
                <description>
                    <![CDATA[<p>There's a saying in Holland that translates to (literally): "<em>A good beginning is half the work</em>". While that is a bit of an exaggeration, starting with a good structure to your new Umbraco site can be very important.</p>
<p>Last Friday I was skyping with my friend <a href="http://www.goyaweb.nl">Yannick</a> and he was having a little trouble with redirecting the home node of his site and using my <a href="http://our.umbraco.org/projects/website-utilities/cultiv-search-engine-sitemap"> search engine sitemap package</a>. After some back and forth we eventually came to the ultimate setup.</p>
<p>Basically, there will always be two nodes: "Site settings" and "Home". The settings node is there so a few site-specific settings (like the Google Analytics account) can be stored. It also helps preventing editors from being able to create documents of just any type. By default, under the "Content" node you can create nodes of all kinds and generally, you want to very much limit what they can create to prevent the site from becoming a mess.</p>
<p>You can see an example of this structure in the following image:</p>
<p><img src="https://cultiv.nl/media/4049/structure-example.png" alt="structure-example" width="200" height="272" /></p>
<p>The "Site" node has the hostname(s) of the site set to it, although it doesn't have to have that. Umbraco will present the first node that it finds in the content tree as the homepage of the site.</p>
<p>I've redirected the "Site" node to the "Home" node so that the correct page will be shown to people entering the site. Later on in the development of your site, I'll be using Umbraco's NiceUrl method to point to pages in my site. Some of those NiceUrl calls go to the "Home" page. This will currently point to "/home".</p>
<p>If you've setup your site to redirect using the umbracoRedirect property, you will have created a 302 redirect from "/" to "/home". This is not what you want for two reasons:</p>
<ol>
<li>search engines don't like that there are two pages in the site with the exact same content</li>
<li>search engines know that a 302 redirect means that it's temporary, so they will keep expecting that the "/" and the "/home" pages are supposed to be different</li>
</ol>
<p>Additionally, you will be faced with another, more immediate couple of problems in Umbraco:</p>
<ol>
<li>the altTemplate mechanism controlled by the 404handlers.config gets confused and only works if you prefix the template name with "/home", which would cause a problem with the search engine sitemap package that I mentioned earlier</li>
<li>you are suddenly unable to <a href="http://our.umbraco.org/wiki/reference/umbraco-best-practices/umbracoredirect"> save XSLT files</a> from the built-in editor in Umbraco</li>
</ol>
<p>This is easily fixed though. On the "Site" node, I've put a property of the Content Picker type with the alias of <a href="#" title="Umbraco tip of the week: Redirects">umbracoInternalRedirectId</a> that will not actually do a redirect, but will render whatever node you pick instead of the current node. Logically, I have picked the "Home" node.</p>
<p>This leaves you with a bit of a problem still, as Umbraco's NiceUrl method still produces links to "/home". To solve this, you can just do a simple urlRewrite and make the "/home" call always do a 301 (permanently moved) redirect to "/". Just the way search engines like it. Be careful: this will cause an infinite loop if you do it while the umbracoRedirect property is still on there, only do this with the <strong>umbracoInternalRedirectId</strong> property.</p>
<p>The urlRewrite config looks like this (note the "$" at the end of "home" is there to make sure that if you want any nodes under your home page, they won't be rewritten as well):</p>
<pre class="brush: xml">&lt;add name="home"<br />
virtualUrl= "^~/home$"<br />
rewriteUrlParameter="ExcludeFromClientQueryString"<br />
destinationUrl="~/"<br />
ignoreCase="true"<br />
redirect="Application"<br />
redirectMode="Permanent" /&gt;
</pre>
<p>And there you have it, the "ultimate" site structure for you to start your site with. Google is happy, Umbraco is happy (it will save your XSLT files again), everybody is happy!</p>
<p><em>That being said, this will probably be my last blog post for this year. Happy holidays and see you next year.</em></p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>There's a saying in Holland that translates to (literally): "<em>A good beginning is half the work</em>". While that is a bit of an exaggeration, starting with a good structure to your new Umbraco site can be very important.</p>
<p>Last Friday I was skyping with my friend <a href="http://www.goyaweb.nl">Yannick</a> and he was having a little trouble with redirecting the home node of his site and using my <a href="http://our.umbraco.org/projects/website-utilities/cultiv-search-engine-sitemap"> search engine sitemap package</a>. After some back and forth we eventually came to the ultimate setup.</p>
<p>Basically, there will always be two nodes: "Site settings" and "Home". The settings node is there so a few site-specific settings (like the Google Analytics account) can be stored. It also helps preventing editors from being able to create documents of just any type. By default, under the "Content" node you can create nodes of all kinds and generally, you want to very much limit what they can create to prevent the site from becoming a mess.</p>
<p>You can see an example of this structure in the following image:</p>
<p><img src="https://cultiv.nl/media/4049/structure-example.png" alt="structure-example" width="200" height="272" /></p>
<p>The "Site" node has the hostname(s) of the site set to it, although it doesn't have to have that. Umbraco will present the first node that it finds in the content tree as the homepage of the site.</p>
<p>I've redirected the "Site" node to the "Home" node so that the correct page will be shown to people entering the site. Later on in the development of your site, I'll be using Umbraco's NiceUrl method to point to pages in my site. Some of those NiceUrl calls go to the "Home" page. This will currently point to "/home".</p>
<p>If you've setup your site to redirect using the umbracoRedirect property, you will have created a 302 redirect from "/" to "/home". This is not what you want for two reasons:</p>
<ol>
<li>search engines don't like that there are two pages in the site with the exact same content</li>
<li>search engines know that a 302 redirect means that it's temporary, so they will keep expecting that the "/" and the "/home" pages are supposed to be different</li>
</ol>
<p>Additionally, you will be faced with another, more immediate couple of problems in Umbraco:</p>
<ol>
<li>the altTemplate mechanism controlled by the 404handlers.config gets confused and only works if you prefix the template name with "/home", which would cause a problem with the search engine sitemap package that I mentioned earlier</li>
<li>you are suddenly unable to <a href="http://our.umbraco.org/wiki/reference/umbraco-best-practices/umbracoredirect"> save XSLT files</a> from the built-in editor in Umbraco</li>
</ol>
<p>This is easily fixed though. On the "Site" node, I've put a property of the Content Picker type with the alias of <a href="#" title="Umbraco tip of the week: Redirects">umbracoInternalRedirectId</a> that will not actually do a redirect, but will render whatever node you pick instead of the current node. Logically, I have picked the "Home" node.</p>
<p>This leaves you with a bit of a problem still, as Umbraco's NiceUrl method still produces links to "/home". To solve this, you can just do a simple urlRewrite and make the "/home" call always do a 301 (permanently moved) redirect to "/". Just the way search engines like it. Be careful: this will cause an infinite loop if you do it while the umbracoRedirect property is still on there, only do this with the <strong>umbracoInternalRedirectId</strong> property.</p>
<p>The urlRewrite config looks like this (note the "$" at the end of "home" is there to make sure that if you want any nodes under your home page, they won't be rewritten as well):</p>
<pre class="brush: xml">&lt;add name="home"<br />
virtualUrl= "^~/home$"<br />
rewriteUrlParameter="ExcludeFromClientQueryString"<br />
destinationUrl="~/"<br />
ignoreCase="true"<br />
redirect="Application"<br />
redirectMode="Permanent" /&gt;
</pre>
<p>And there you have it, the "ultimate" site structure for you to start your site with. Google is happy, Umbraco is happy (it will save your XSLT files again), everybody is happy!</p>
<p><em>That being said, this will probably be my last blog post for this year. Happy holidays and see you next year.</em></p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Making Contour even sexier</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/making-contour-even-sexier/</link>
                <pubDate>Thu, 18 Nov 2010 22:26:43 GMT</pubDate>
                <guid>https://cultiv.nl/blog/making-contour-even-sexier/</guid>
                <description>
                    <![CDATA[<p>So Contour for Umbraco is really, really cool, that much is for sure!</p>
<p>But.. Styling forms is really hard! You have to hack a lot of CSS to make a moderately sexy looking form.</p>
<p>I am not a frontend developer so this usually ends badly. In fact, up until now, I've not used Contour for a lot of sites because the form styling was so difficult to do. For example, how would you do something a little different looking, like this:</p>
<p style="text-align: center;"><img src="https://cultiv.nl/media/3965/restcontourexample_500x383.jpg" alt="restcontourexample" width="500" height="383" /></p>
<p>This is all changing. I <a href="http://our.umbraco.org/projects/website-utilities/cultiv-restcontour"> recently released the RestContour package</a>, that lets you post from any form into Contour. Currently I'm working on making this very very easy to use, and make it look sexy in the process. I've used the RestContour package for an upcoming website and have made it even better. Now you can just use any old HTML form easily and make it into a Contour form, validation and all, with very little effort.</p>
<p>Check out the video below:</p>
<p style="text-align: center;"><object width="480" height="385" data="http://www.youtube.com/v/TJG2u-9CuRY?fs=1&amp;hl=en_US&amp;rel=0" type="application/x-shockwave-flash"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/TJG2u-9CuRY?fs=1&amp;hl=en_US&amp;rel=0" /><param name="allowfullscreen" value="true" /></object></p>
<p>You can download this version of the RestContour package from <a href="http://our.umbraco.org/projects/website-utilities/cultiv-restcontour"> the project page</a> (RestContourPreview_0.8.0.zip) and the source (Cultiv.RestContour.7z) is also available.</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>So Contour for Umbraco is really, really cool, that much is for sure!</p>
<p>But.. Styling forms is really hard! You have to hack a lot of CSS to make a moderately sexy looking form.</p>
<p>I am not a frontend developer so this usually ends badly. In fact, up until now, I've not used Contour for a lot of sites because the form styling was so difficult to do. For example, how would you do something a little different looking, like this:</p>
<p style="text-align: center;"><img src="https://cultiv.nl/media/3965/restcontourexample_500x383.jpg" alt="restcontourexample" width="500" height="383" /></p>
<p>This is all changing. I <a href="http://our.umbraco.org/projects/website-utilities/cultiv-restcontour"> recently released the RestContour package</a>, that lets you post from any form into Contour. Currently I'm working on making this very very easy to use, and make it look sexy in the process. I've used the RestContour package for an upcoming website and have made it even better. Now you can just use any old HTML form easily and make it into a Contour form, validation and all, with very little effort.</p>
<p>Check out the video below:</p>
<p style="text-align: center;"><object width="480" height="385" data="http://www.youtube.com/v/TJG2u-9CuRY?fs=1&amp;hl=en_US&amp;rel=0" type="application/x-shockwave-flash"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/TJG2u-9CuRY?fs=1&amp;hl=en_US&amp;rel=0" /><param name="allowfullscreen" value="true" /></object></p>
<p>You can download this version of the RestContour package from <a href="http://our.umbraco.org/projects/website-utilities/cultiv-restcontour"> the project page</a> (RestContourPreview_0.8.0.zip) and the source (Cultiv.RestContour.7z) is also available.</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Using &quot;/base&quot; to create and consume a JSON string</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/using-base-to-create-and-consume-a-json-string/</link>
                <pubDate>Tue, 12 Oct 2010 19:49:11 GMT</pubDate>
                <guid>https://cultiv.nl/blog/using-base-to-create-and-consume-a-json-string/</guid>
                <description>
                    <![CDATA[<p>So, you want to create and use javascript objects in Umbraco!</p>
<p>Not a problem. I'll be showing you an example using "/base", <a href="http://james.newtonking.com/pages/json-net.aspx">Json.NET</a> and a little bit of what I'm doing with <a href="http://umbraco.org/contour">Contour</a> at the moment.</p>
<p><strong>/base</strong><br /> Umbraco's "/base" is an <a href="http://umbraco.org/documentation/books/introduction-to-base">extendable system for creating raw feeds directly from Umbraco using very basic Url's</a>.&nbsp;These feeds are typically in XML format but it's very easy to create a JSON feed instead of an XML one. The way /base works is by mapping a method to a URL through a config file (see the above link for an introduction).</p>
<p><strong>JSON</strong><br /> In javascript you can use JSON (JavaScript Object Notation) to access data. A JSON object is just an array of strings, like so:</p>
<pre class="brush: xml">"person": {<br />
"name": "Sebastiaan Janssen",&nbsp;<br />
"country": "The Netherlands"<br />
}
</pre>
<p>You can access the information in this object by evaluating this string in javascript. Let's say the above JSON string was in a variable called "json":</p>
<pre class="brush: css">var result = eval("(" + json + ")");<br />
var name = result.person[0].name;
</pre>
<p>The variable "name" will now be filled with the string "Sebastiaan Janssen". To make sure the evaluation will work, you need to surround the JSON string with braces, which is what I've done on the first line.</p>
<p><strong>Json.NET</strong><br /> So how great would it be if you could just output any old .net class as a JSON string, so you could easily use it in javascript? With Json.NET you can do just that! Have a look at <a href="http://contourcontrib.codeplex.com/SourceControl/changeset/view/3407#60876"> a simple example</a> in the source of my RESTContour package. The GetJsonForObject method accepts any object and spits out a JSON string, great!</p>
<p><strong>Putting it all together</strong><br /> So let's combine all of the above. Create a method that outputs a string, the string will contain some JSON. Normally, a call to a /base method will result in some XML output, but we want a string.</p>
<p>In the restExtensions.config file there's a "permission" node, add a new attribute&nbsp;<strong>returnXml="false"</strong> to it so that the output will just be a string.</p>
<p>Now we can make an AJAX call (using a little <a href="http://jquery.com/">jQuery</a>) to the /base URL and evaluate the result. Going back to the RESTContour example class mentioned above, I am going to get all of the available Contour forms and alert the form names.</p>
<pre class="brush: xml">$(document).ready(function () {
var getFormUrl = "/base/getContourForm/GetAllForms";

$.ajax({
url: getFormUrl,
success: function (data) {
var result = eval("(" + data + ")");

for (var i = 0; i &lt; result.length; i++) {
alert(result[i].Name);
}
}
});
});
</pre>
<p>As said, you can output just about any object as a JSON string using base, which can be very useful, try it out!</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>So, you want to create and use javascript objects in Umbraco!</p>
<p>Not a problem. I'll be showing you an example using "/base", <a href="http://james.newtonking.com/pages/json-net.aspx">Json.NET</a> and a little bit of what I'm doing with <a href="http://umbraco.org/contour">Contour</a> at the moment.</p>
<p><strong>/base</strong><br /> Umbraco's "/base" is an <a href="http://umbraco.org/documentation/books/introduction-to-base">extendable system for creating raw feeds directly from Umbraco using very basic Url's</a>.&nbsp;These feeds are typically in XML format but it's very easy to create a JSON feed instead of an XML one. The way /base works is by mapping a method to a URL through a config file (see the above link for an introduction).</p>
<p><strong>JSON</strong><br /> In javascript you can use JSON (JavaScript Object Notation) to access data. A JSON object is just an array of strings, like so:</p>
<pre class="brush: xml">"person": {<br />
"name": "Sebastiaan Janssen",&nbsp;<br />
"country": "The Netherlands"<br />
}
</pre>
<p>You can access the information in this object by evaluating this string in javascript. Let's say the above JSON string was in a variable called "json":</p>
<pre class="brush: css">var result = eval("(" + json + ")");<br />
var name = result.person[0].name;
</pre>
<p>The variable "name" will now be filled with the string "Sebastiaan Janssen". To make sure the evaluation will work, you need to surround the JSON string with braces, which is what I've done on the first line.</p>
<p><strong>Json.NET</strong><br /> So how great would it be if you could just output any old .net class as a JSON string, so you could easily use it in javascript? With Json.NET you can do just that! Have a look at <a href="http://contourcontrib.codeplex.com/SourceControl/changeset/view/3407#60876"> a simple example</a> in the source of my RESTContour package. The GetJsonForObject method accepts any object and spits out a JSON string, great!</p>
<p><strong>Putting it all together</strong><br /> So let's combine all of the above. Create a method that outputs a string, the string will contain some JSON. Normally, a call to a /base method will result in some XML output, but we want a string.</p>
<p>In the restExtensions.config file there's a "permission" node, add a new attribute&nbsp;<strong>returnXml="false"</strong> to it so that the output will just be a string.</p>
<p>Now we can make an AJAX call (using a little <a href="http://jquery.com/">jQuery</a>) to the /base URL and evaluate the result. Going back to the RESTContour example class mentioned above, I am going to get all of the available Contour forms and alert the form names.</p>
<pre class="brush: xml">$(document).ready(function () {
var getFormUrl = "/base/getContourForm/GetAllForms";

$.ajax({
url: getFormUrl,
success: function (data) {
var result = eval("(" + data + ")");

for (var i = 0; i &lt; result.length; i++) {
alert(result[i].Name);
}
}
});
});
</pre>
<p>As said, you can output just about any object as a JSON string using base, which can be very useful, try it out!</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>PhotoMetaData package now available</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/photometadata-package-now-available/</link>
                <pubDate>Sat, 17 Jul 2010 14:51:35 GMT</pubDate>
                <guid>https://cultiv.nl/blog/photometadata-package-now-available/</guid>
                <description>
                    <![CDATA[<p><img class="imgRight" src="https://cultiv.nl/media/3568/4735128485_ff558e1c32.jpg" alt="4735128485_ff558e1c32" width="167" height="250" />On Codegarden '10 I entered the package competition on a whim, after installing the shiny new Umbraco 4.5 on my laptop there. I was inspired to try and see if the package that I had not completely completed would work on 4.5 and when it did, I just added my name to the list. I ended up winning the third prize with it (a brand new Xbox 360 Elite)!</p>
<p>I've since polished the code a little bit and it is now available to <a href="http://our.umbraco.org/projects/website-utilities/cultiv-photometadata"> download from the projects section at our.umbraco.org</a>.</p>
<p>Of course I expect to get as many votes on Our Umbraco as during the package contest (you rock)!</p>
<p>The PhotoMetaData package will extract meta data from images that you upload in your media section. <em>This works in both Umbraco 4.0.x and 4.5.</em></p>
<p>When you create a property with the correct name it will be filled as soon as you upload an image in the media section.</p>
<p>Here a video with a quick overview of the package.</p>
<p style="text-align: center;"><object width="549" height="334" data="https://www.youtube.com/v/Tb7OPkmfk7c&amp;hl=en_US&amp;fs=1?rel=0&amp;hd=1" type="application/x-shockwave-flash" style="display: none !important;"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="https://www.youtube.com/v/Tb7OPkmfk7c&amp;hl=en_US&amp;fs=1?rel=0&amp;hd=1" /><param name="allowfullscreen" value="true" /></object></p>
<div class="flc-panel" style="width: 549px; height: 334px; top: auto; left: auto; display: block !important;"></div>
<div class="flc-panel" style="width: 549px; height: 334px; top: auto; left: auto; display: block !important;"></div>
<p><em>Photo by the wonderful</em> <a href="http://twitter.com/drobar"><em>Douglas Robar</em></a></p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p><img class="imgRight" src="https://cultiv.nl/media/3568/4735128485_ff558e1c32.jpg" alt="4735128485_ff558e1c32" width="167" height="250" />On Codegarden '10 I entered the package competition on a whim, after installing the shiny new Umbraco 4.5 on my laptop there. I was inspired to try and see if the package that I had not completely completed would work on 4.5 and when it did, I just added my name to the list. I ended up winning the third prize with it (a brand new Xbox 360 Elite)!</p>
<p>I've since polished the code a little bit and it is now available to <a href="http://our.umbraco.org/projects/website-utilities/cultiv-photometadata"> download from the projects section at our.umbraco.org</a>.</p>
<p>Of course I expect to get as many votes on Our Umbraco as during the package contest (you rock)!</p>
<p>The PhotoMetaData package will extract meta data from images that you upload in your media section. <em>This works in both Umbraco 4.0.x and 4.5.</em></p>
<p>When you create a property with the correct name it will be filled as soon as you upload an image in the media section.</p>
<p>Here a video with a quick overview of the package.</p>
<p style="text-align: center;"><object width="549" height="334" data="https://www.youtube.com/v/Tb7OPkmfk7c&amp;hl=en_US&amp;fs=1?rel=0&amp;hd=1" type="application/x-shockwave-flash" style="display: none !important;"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="https://www.youtube.com/v/Tb7OPkmfk7c&amp;hl=en_US&amp;fs=1?rel=0&amp;hd=1" /><param name="allowfullscreen" value="true" /></object></p>
<div class="flc-panel" style="width: 549px; height: 334px; top: auto; left: auto; display: block !important;"></div>
<div class="flc-panel" style="width: 549px; height: 334px; top: auto; left: auto; display: block !important;"></div>
<p><em>Photo by the wonderful</em> <a href="http://twitter.com/drobar"><em>Douglas Robar</em></a></p>]]>
                </content:encoded>
            </item>
            <item>
                <title>SEO optimizing in Umbraco</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/seo-optimizing-in-umbraco/</link>
                <pubDate>Wed, 07 Apr 2010 17:43:39 GMT</pubDate>
                <guid>https://cultiv.nl/blog/seo-optimizing-in-umbraco/</guid>
                <description>
                    <![CDATA[<p>Just a few weeks ago, someone showed me <a href="http://woorank.com">woorank</a>, a very cool website analysis tool. Woorank tells you what you can improve on your website to help search engines find and evaluate your content better.</p>
<p>By giving you a score from 0 to 100, you can easily compare your site to others. The score is divided up in dozens of different indicators that all have a certain weight in the calculation of the score. All of the indicators are nicely explained to help you understand why they're there (and if you should care about them).</p>
<p>My site actually scored pretty well (56 at the time). Of course I don't have an entry in wikipedia and my Alexa rank really sucks, so no points there. Fair enough.</p>
<p>I found that I could easily improve my score by tweaking some things in my site, mostly using content that I already had available anyway. Umbraco makes this really, really easy. No programming needed, mostly tweaks to my templates / XSLT files. Here's what I did (and what anybody could do!).</p>
<h3>Sitemap</h3>
<p>Of course I already have a sitemap on my site thanks to my own fantastically simple sitemap package (it's just a bit of XSLT, really, have you voted yet?).</p>
<p>However, woorank told me that a sitemap was missing. Of course, I have no link to the sitemap anywhere and it's not called sitemap.xml. So I thought I'd find out how to let search engines (and woorank) know that I have one available to crawl.</p>
<p>First of all, you can include a meta tag in the head of your HTML. Easy enough, just add it to the template, <a href="http://sebastians-pamphlets.com/is-xml-sitemap-autodiscovery-for-everyone/"> but this won't always work</a>. Google, for example, relies on the sitemap being in your robots.txt file. Unfortunately, the robots.txt can't be edited from within Umbraco, so I had to make this improvement by updating it manually.</p>
<h3>Microformats</h3>
<p>Jeff Atwood of <a href="http://codinghorror.com">Coding Horror</a> and <a href="http://stackoverflow.com">StackOverflow</a> fame wrote a <a href="http://www.codinghorror.comhttps://cultiv.nl/blog/2009/12/microformats-boon-or-bane.html"> blog post</a> in December about making crappy HTML even more crappy by putting extra crappy HTML in it to support microformats. In the end though, he concludes that it's too easy <strong>not</strong> to do.</p>
<p>I don't really see the added value at the moment, but it can't hurt to implement some of it.</p>
<p>The only microformat that I could think of would make sense on my site was the contact information, using the <a href="http://microformats.org/wiki/hCard">hCard format</a>. So off I went, added some div's and spans in my footer XSLT and in the HTML on the contact page.</p>
<h3>Dublin Core</h3>
<p>What's this you ask? I had no idea either. As it turns out <a href="http://dublincore.org/documents/usageguide/">Dublin Core meta data</a> is very structured information about the page you're currently on. Although, it seems only <strong>slightly</strong> better than the normal meta description / keywords tag.</p>
<p>As with the microformats, it doesn't hurt, so I spent 5 minutes updating my main template to include Dublin Core data (title, description, creator &amp; publisher). This data was easily accessible from Umbraco and I'd already used most of it in the other meta tags, so a quick copy &amp; paste in the template did the trick.</p>
<h3>Geo Meta Tags</h3>
<p>Oh boy, even <strong>more</strong> meta tags. Alright, geographic information. The content of my site isn't targeted at a specific geographic location, nor does it show any data that belongs to a location. I suppose it's nice to know that I'm in The Hague. Once again, too easy not to do, so I added the <a href="http://dublincore.org/documents/usageguide/">placename, region and coordinates</a> to the template.</p>
<h3>Conclusion</h3>
<p>There is a lot of meta data out there. And apparently, search engines actually look for that information. I do get the impression, though, that there is too many different formats. Can we just pick one and stick with it? Oh wait, it's the web, when has that ever happened?</p>
<p>It took me a few hours to figure out what information was needed everywhere, but once I did, Umbraco made it painless for me to update my entire site using existing data.</p>
<p>This will be even more fun when I start adding the geo information to the site I'm currently working on that shows panorama pictures. Each picture already has GPS coordinates so it'll be a really quick XSLT addition.</p>
<div><span><br /> </span></div>
<div><span><br /> </span></div>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Just a few weeks ago, someone showed me <a href="http://woorank.com">woorank</a>, a very cool website analysis tool. Woorank tells you what you can improve on your website to help search engines find and evaluate your content better.</p>
<p>By giving you a score from 0 to 100, you can easily compare your site to others. The score is divided up in dozens of different indicators that all have a certain weight in the calculation of the score. All of the indicators are nicely explained to help you understand why they're there (and if you should care about them).</p>
<p>My site actually scored pretty well (56 at the time). Of course I don't have an entry in wikipedia and my Alexa rank really sucks, so no points there. Fair enough.</p>
<p>I found that I could easily improve my score by tweaking some things in my site, mostly using content that I already had available anyway. Umbraco makes this really, really easy. No programming needed, mostly tweaks to my templates / XSLT files. Here's what I did (and what anybody could do!).</p>
<h3>Sitemap</h3>
<p>Of course I already have a sitemap on my site thanks to my own fantastically simple sitemap package (it's just a bit of XSLT, really, have you voted yet?).</p>
<p>However, woorank told me that a sitemap was missing. Of course, I have no link to the sitemap anywhere and it's not called sitemap.xml. So I thought I'd find out how to let search engines (and woorank) know that I have one available to crawl.</p>
<p>First of all, you can include a meta tag in the head of your HTML. Easy enough, just add it to the template, <a href="http://sebastians-pamphlets.com/is-xml-sitemap-autodiscovery-for-everyone/"> but this won't always work</a>. Google, for example, relies on the sitemap being in your robots.txt file. Unfortunately, the robots.txt can't be edited from within Umbraco, so I had to make this improvement by updating it manually.</p>
<h3>Microformats</h3>
<p>Jeff Atwood of <a href="http://codinghorror.com">Coding Horror</a> and <a href="http://stackoverflow.com">StackOverflow</a> fame wrote a <a href="http://www.codinghorror.comhttps://cultiv.nl/blog/2009/12/microformats-boon-or-bane.html"> blog post</a> in December about making crappy HTML even more crappy by putting extra crappy HTML in it to support microformats. In the end though, he concludes that it's too easy <strong>not</strong> to do.</p>
<p>I don't really see the added value at the moment, but it can't hurt to implement some of it.</p>
<p>The only microformat that I could think of would make sense on my site was the contact information, using the <a href="http://microformats.org/wiki/hCard">hCard format</a>. So off I went, added some div's and spans in my footer XSLT and in the HTML on the contact page.</p>
<h3>Dublin Core</h3>
<p>What's this you ask? I had no idea either. As it turns out <a href="http://dublincore.org/documents/usageguide/">Dublin Core meta data</a> is very structured information about the page you're currently on. Although, it seems only <strong>slightly</strong> better than the normal meta description / keywords tag.</p>
<p>As with the microformats, it doesn't hurt, so I spent 5 minutes updating my main template to include Dublin Core data (title, description, creator &amp; publisher). This data was easily accessible from Umbraco and I'd already used most of it in the other meta tags, so a quick copy &amp; paste in the template did the trick.</p>
<h3>Geo Meta Tags</h3>
<p>Oh boy, even <strong>more</strong> meta tags. Alright, geographic information. The content of my site isn't targeted at a specific geographic location, nor does it show any data that belongs to a location. I suppose it's nice to know that I'm in The Hague. Once again, too easy not to do, so I added the <a href="http://dublincore.org/documents/usageguide/">placename, region and coordinates</a> to the template.</p>
<h3>Conclusion</h3>
<p>There is a lot of meta data out there. And apparently, search engines actually look for that information. I do get the impression, though, that there is too many different formats. Can we just pick one and stick with it? Oh wait, it's the web, when has that ever happened?</p>
<p>It took me a few hours to figure out what information was needed everywhere, but once I did, Umbraco made it painless for me to update my entire site using existing data.</p>
<p>This will be even more fun when I start adding the geo information to the site I'm currently working on that shows panorama pictures. Each picture already has GPS coordinates so it'll be a really quick XSLT addition.</p>
<div><span><br /> </span></div>
<div><span><br /> </span></div>]]>
                </content:encoded>
            </item>
            <item>
                <title>Convert between VS2008 and 2010 projects, automatically</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/convert-between-vs2008-and-2010-projects-automatically/</link>
                <pubDate>Tue, 16 Mar 2010 19:32:58 GMT</pubDate>
                <guid>https://cultiv.nl/blog/convert-between-vs2008-and-2010-projects-automatically/</guid>
                <description>
                    <![CDATA[<p>Recently, I was told that I was being a bother and that I shouldn't develop in VS2010. Sure, the current RC is not the final version, but it's a release candidate, not much will change between now and the RTM (unless something really bad happens). But sometimes you need to conform and give people what they want. Back to VS2008 I went.</p>
<p>I love working with the latest and greatest though, so in a few spare hours just now I have been plotting and scheming and came up with a brilliant solution to thwart the command of my opresser, muhahaha!</p>
<p>Yes, I did it, I created a tool that can convert my complete VS2010 project back to a VS2008 project so that I can commit my code without my opponent knowing worked in VS2010.</p>
<p>This is done, very simply by replacing a few strings in the <em>.sln</em> and <em>.csproj</em> files. Now, this is a simple approach and it will throw away some information that is new to VS2010. However, it works for my purposes and I'm sharing it here so that people will be able to build upon it if they wish, or use it as is.</p>
<p><strong>Mind you, there is NO GUARANTEES and I'm sure this is going to kill your project if you're not careful!</strong></p>
<p>Was that proper warning? Okay, well here it is: two old-school batch files and a tool to do the string replacements (which I got from <a href="http://www.programmersheaven.com/download/41236/download.aspx"> programmersheaven</a>).</p>
<p>You can now download <a href="https://cultiv.nl/media/2958/convertbetweenvs2010and2008.zip">the fully automated VS2008 to VS2010 converter</a>, enjoy.</p>
<p>Oh HAI <a href="http://twitter.com/gerbenvdiggelen/">Gerben</a>, didn't know you were going to read this...</p>
<p><img src="https://cultiv.nl/media/2953/funny-pictures-cat-goes-on-the-naughty-list.jpg" alt="funny-pictures-cat-goes-on-the-naughty-list" width="500" height="333" /></p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Recently, I was told that I was being a bother and that I shouldn't develop in VS2010. Sure, the current RC is not the final version, but it's a release candidate, not much will change between now and the RTM (unless something really bad happens). But sometimes you need to conform and give people what they want. Back to VS2008 I went.</p>
<p>I love working with the latest and greatest though, so in a few spare hours just now I have been plotting and scheming and came up with a brilliant solution to thwart the command of my opresser, muhahaha!</p>
<p>Yes, I did it, I created a tool that can convert my complete VS2010 project back to a VS2008 project so that I can commit my code without my opponent knowing worked in VS2010.</p>
<p>This is done, very simply by replacing a few strings in the <em>.sln</em> and <em>.csproj</em> files. Now, this is a simple approach and it will throw away some information that is new to VS2010. However, it works for my purposes and I'm sharing it here so that people will be able to build upon it if they wish, or use it as is.</p>
<p><strong>Mind you, there is NO GUARANTEES and I'm sure this is going to kill your project if you're not careful!</strong></p>
<p>Was that proper warning? Okay, well here it is: two old-school batch files and a tool to do the string replacements (which I got from <a href="http://www.programmersheaven.com/download/41236/download.aspx"> programmersheaven</a>).</p>
<p>You can now download <a href="https://cultiv.nl/media/2958/convertbetweenvs2010and2008.zip">the fully automated VS2008 to VS2010 converter</a>, enjoy.</p>
<p>Oh HAI <a href="http://twitter.com/gerbenvdiggelen/">Gerben</a>, didn't know you were going to read this...</p>
<p><img src="https://cultiv.nl/media/2953/funny-pictures-cat-goes-on-the-naughty-list.jpg" alt="funny-pictures-cat-goes-on-the-naughty-list" width="500" height="333" /></p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Umbraco - Object reference not set..</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/umbraco-object-reference-not-set/</link>
                <pubDate>Mon, 08 Mar 2010 16:16:34 GMT</pubDate>
                <guid>https://cultiv.nl/blog/umbraco-object-reference-not-set/</guid>
                <description>
                    <![CDATA[<p>Today, I had a little problem after adding some properties to a document type in Umbraco. I've had this problem before and I keep forgetting how to fix it.</p>
<p>When opening a node of this document type (in Umbraco's Content area, not the document type editor), I get the following (rather generic) error:</p>
<p>I must add that while creating some new properties on this document type, the property was added, but I did get and SQL time-out. Not sure why that was, but it must have interupted an update process on existing nodes.</p>
<p>This is probably the reason that the current nodes are now corrupt. As you can see in the exception, there was a problem adding a control to the page.</p>
<p>The solution is easy, you have to publish all of the nodes and its subpages to fix the error. Voli&aacute;!</p>
<p><em>Richard Soeteman</em> adds some extra information on a similar error while deleting a property on a document type. The issues could be related, so if you still have problems, check out <a href="http://www.richardsoeteman.net/2009/10/27/FixObjectReferenceNotSetErrorAfterAddingOrDeletingADocumentProperty.aspx"> his blog post</a> as well.</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Today, I had a little problem after adding some properties to a document type in Umbraco. I've had this problem before and I keep forgetting how to fix it.</p>
<p>When opening a node of this document type (in Umbraco's Content area, not the document type editor), I get the following (rather generic) error:</p>
<p>I must add that while creating some new properties on this document type, the property was added, but I did get and SQL time-out. Not sure why that was, but it must have interupted an update process on existing nodes.</p>
<p>This is probably the reason that the current nodes are now corrupt. As you can see in the exception, there was a problem adding a control to the page.</p>
<p>The solution is easy, you have to publish all of the nodes and its subpages to fix the error. Voli&aacute;!</p>
<p><em>Richard Soeteman</em> adds some extra information on a similar error while deleting a property on a document type. The issues could be related, so if you still have problems, check out <a href="http://www.richardsoeteman.net/2009/10/27/FixObjectReferenceNotSetErrorAfterAddingOrDeletingADocumentProperty.aspx"> his blog post</a> as well.</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Umbraco MVP - Don&#39;t vote for me</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/umbraco-mvp-dont-vote-for-me/</link>
                <pubDate>Fri, 05 Feb 2010 13:27:27 GMT</pubDate>
                <guid>https://cultiv.nl/blog/umbraco-mvp-dont-vote-for-me/</guid>
                <description>
                    <![CDATA[<p>Wow, who would've thought 10 months ago when I was introduced to Umbraco that I would be <a href="http://umbraco.orghttps://cultiv.nl/blog/2010/2/5/time-to-vote-for-the-2010-umbraco-mvps"> nominated</a> to be an MVP? I sure didn't expect that!</p>
<p>I'm not asking for votes, I'm proud to be listed among giants and you can make your own decisions.</p>
<p>However, I would like to promote the others on the list:</p>
<p><strong><img style="outline-width: 0px; outline-style: initial; outline-color: initial; font-size: 15px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; background-position: initial initial; background-repeat: initial initial; padding: 0px; margin: 0px; border: 0px initial initial;" src="https://cultiv.nl/media/2731/vote-706542.jpg" alt="vote-706542" width="300" height="379" align="right" />Chris Houston</strong> was the first one to reply on my first blog post and I love how active and involved he is in the community. I can't wait to see the cmsMailer package that he's involved in. Vote for Chris!</p>
<p><strong>Chris Koiak</strong> has made some cool packages and seems to be a great developer with a passion for Umbraco. Besides, he's from Glasgow, he must have a great accent. Vote for Chris (no, not the other one, this one)!</p>
<p><strong>Dan Drayne</strong> must have a very high accept rate on our.umbraco, his forum replies are always very helpful. Vote for Dan!</p>
<p><strong>Darren Ferguson</strong>'s source code makes me jealous! Awesome packages, I have a lot to learn from this guy. Vote for Darren!</p>
<p><strong>Dirk De Grave</strong> is always helpful on the forum, always there (does he ever leave his computer?), patient beyond belief even though some people test his patience sometimes. Vote for Dirk!</p>
<p><strong>Douglas Robar</strong> really is the best teacher I've ever met. His posts on the forum are long and complete, with amazing attention to detail. Vote for Douglas!</p>
<p><strong>Jan Skovgaard</strong> also always seem to be online, helping out, asking questions. Plus he seems to like Dutch people, perfect! Vote for Jan!</p>
<p><strong>Jesper Ordrup</strong> seems to be taking Umbraco to new heights with the projects he's involved in. Let's hope he keeps sharing his insights. Vote for Jesper!</p>
<p><strong>Lee Kelleher</strong> is a busy bee, he seems to be everywhere at the same time and should be rewarded for all of his efforts in the community. Vote for Lee!</p>
<p><strong>Lee Messenger</strong>'s ideas to change the our.umbraco forum from "just" questions and answer to even more thought provoking conversations are great, keep up the good work. Vote for Lee (THIS one)!</p>
<p><strong>Morten Bock</strong>:&nbsp;uForum, need I say more? Awesome coder. Vote for Morten!</p>
<p><strong>Nik Wahlberg</strong> I don't know so well unfortunately, but he must be awesome 'cause he's wearing sunglasses, just like Niels. Vote for Nik!</p>
<p><strong>Peter Dijksterhuis</strong> should win because he works on a farm one month a year. Also, he made the great calendar package, good stuff. Vote for Peter!</p>
<p><strong>Petr Snobelt</strong> thumbs up for the MemberControls package, and his avatar. Vote for Petr!</p>
<p><strong>Richard Soeteman</strong> is the number one Umbraco fanboy from The Netherlands. This guy might be singlehandedly responsible for the rise in popularity of Umbraco in the last year or so.. ;) Vote for Richard!</p>
<p><strong>Ron Brouwer</strong> another fellow Dutchie and a very helpful guy, love his work. Vote for Ron!</p>
<p><strong>Thomas H&ouml;hler</strong> must be the loneliest Umbracian in Germany, but that's great, gives him time to help everybody out on the forum and on Twitter. Also makes cool packages. Vote for Thomas!</p>
<p><strong>Tim Saunders</strong> always helpful with a different take things, I love seeing alternate solutions. Vote for Tim!</p>
<p><strong>Warren Buckley</strong> well, what's not to love about this guy, CWS is awesome, he's always looking to add value to the community, and it's working. Vote for Warren!</p>
<p>... I really can't choose, I might as well vote for myself now!</p>
<p>Of course, this is all a clever ploy to get everybody to vote for me anyway.. I trust you will all not find me out. ;-)</p>
<p>&nbsp;</p>
<div><span><br /> </span></div>
<div><span><br /> </span></div>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Wow, who would've thought 10 months ago when I was introduced to Umbraco that I would be <a href="http://umbraco.orghttps://cultiv.nl/blog/2010/2/5/time-to-vote-for-the-2010-umbraco-mvps"> nominated</a> to be an MVP? I sure didn't expect that!</p>
<p>I'm not asking for votes, I'm proud to be listed among giants and you can make your own decisions.</p>
<p>However, I would like to promote the others on the list:</p>
<p><strong><img style="outline-width: 0px; outline-style: initial; outline-color: initial; font-size: 15px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; background-position: initial initial; background-repeat: initial initial; padding: 0px; margin: 0px; border: 0px initial initial;" src="https://cultiv.nl/media/2731/vote-706542.jpg" alt="vote-706542" width="300" height="379" align="right" />Chris Houston</strong> was the first one to reply on my first blog post and I love how active and involved he is in the community. I can't wait to see the cmsMailer package that he's involved in. Vote for Chris!</p>
<p><strong>Chris Koiak</strong> has made some cool packages and seems to be a great developer with a passion for Umbraco. Besides, he's from Glasgow, he must have a great accent. Vote for Chris (no, not the other one, this one)!</p>
<p><strong>Dan Drayne</strong> must have a very high accept rate on our.umbraco, his forum replies are always very helpful. Vote for Dan!</p>
<p><strong>Darren Ferguson</strong>'s source code makes me jealous! Awesome packages, I have a lot to learn from this guy. Vote for Darren!</p>
<p><strong>Dirk De Grave</strong> is always helpful on the forum, always there (does he ever leave his computer?), patient beyond belief even though some people test his patience sometimes. Vote for Dirk!</p>
<p><strong>Douglas Robar</strong> really is the best teacher I've ever met. His posts on the forum are long and complete, with amazing attention to detail. Vote for Douglas!</p>
<p><strong>Jan Skovgaard</strong> also always seem to be online, helping out, asking questions. Plus he seems to like Dutch people, perfect! Vote for Jan!</p>
<p><strong>Jesper Ordrup</strong> seems to be taking Umbraco to new heights with the projects he's involved in. Let's hope he keeps sharing his insights. Vote for Jesper!</p>
<p><strong>Lee Kelleher</strong> is a busy bee, he seems to be everywhere at the same time and should be rewarded for all of his efforts in the community. Vote for Lee!</p>
<p><strong>Lee Messenger</strong>'s ideas to change the our.umbraco forum from "just" questions and answer to even more thought provoking conversations are great, keep up the good work. Vote for Lee (THIS one)!</p>
<p><strong>Morten Bock</strong>:&nbsp;uForum, need I say more? Awesome coder. Vote for Morten!</p>
<p><strong>Nik Wahlberg</strong> I don't know so well unfortunately, but he must be awesome 'cause he's wearing sunglasses, just like Niels. Vote for Nik!</p>
<p><strong>Peter Dijksterhuis</strong> should win because he works on a farm one month a year. Also, he made the great calendar package, good stuff. Vote for Peter!</p>
<p><strong>Petr Snobelt</strong> thumbs up for the MemberControls package, and his avatar. Vote for Petr!</p>
<p><strong>Richard Soeteman</strong> is the number one Umbraco fanboy from The Netherlands. This guy might be singlehandedly responsible for the rise in popularity of Umbraco in the last year or so.. ;) Vote for Richard!</p>
<p><strong>Ron Brouwer</strong> another fellow Dutchie and a very helpful guy, love his work. Vote for Ron!</p>
<p><strong>Thomas H&ouml;hler</strong> must be the loneliest Umbracian in Germany, but that's great, gives him time to help everybody out on the forum and on Twitter. Also makes cool packages. Vote for Thomas!</p>
<p><strong>Tim Saunders</strong> always helpful with a different take things, I love seeing alternate solutions. Vote for Tim!</p>
<p><strong>Warren Buckley</strong> well, what's not to love about this guy, CWS is awesome, he's always looking to add value to the community, and it's working. Vote for Warren!</p>
<p>... I really can't choose, I might as well vote for myself now!</p>
<p>Of course, this is all a clever ploy to get everybody to vote for me anyway.. I trust you will all not find me out. ;-)</p>
<p>&nbsp;</p>
<div><span><br /> </span></div>
<div><span><br /> </span></div>]]>
                </content:encoded>
            </item>
            <item>
                <title>Screencast: Installing Umbraco</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/screencast-installing-umbraco/</link>
                <pubDate>Mon, 01 Feb 2010 00:08:36 GMT</pubDate>
                <guid>https://cultiv.nl/blog/screencast-installing-umbraco/</guid>
                <description>
                    <![CDATA[<p>Rather than making a long post with a lot of images, I decided to do something new for this post: a nice little 6 minute screencast!</p>
<p>It's just a quick run through of how I create a new Umbraco installs on my dev machines. It's easy!</p>
<p>I noticed after the recording that I didn't change the path for the database files. During the creation of the new database, you can easily change the path of where the database files are stored here (buttons marked yellow):</p>
<p style="text-align: center;"> </p>
<p><img style="display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;" src="https://cultiv.nl/media/2646/newdatabase_496x175.jpg" alt="newdatabase" width="496" height="175" /></p>
<p> </p>
<p>I tend to mumble a little, I'll work on that for future screencasts (also, I didn't shave, sorry). ;-)</p>
<p>Hopefully this will help some people setting up their Umbraco install manually.</p>
<p style="text-align: center;"><object width="550" height="437" data="https://www.youtube.com/v/DP4dwzbL8JY&amp;hl=en_US&amp;fs=1" type="application/x-shockwave-flash" style="display: none !important;"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="https://www.youtube.com/v/DP4dwzbL8JY&amp;hl=en_US&amp;fs=1" /><param name="allowfullscreen" value="true" /></object></p>
<div class="flc-panel" style="width: 550px; height: 437px; top: auto; left: auto; display: block !important;"></div>
<div class="flc-panel" style="width: 550px; height: 437px; top: auto; left: auto; display: block !important;"></div>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Rather than making a long post with a lot of images, I decided to do something new for this post: a nice little 6 minute screencast!</p>
<p>It's just a quick run through of how I create a new Umbraco installs on my dev machines. It's easy!</p>
<p>I noticed after the recording that I didn't change the path for the database files. During the creation of the new database, you can easily change the path of where the database files are stored here (buttons marked yellow):</p>
<p style="text-align: center;"> </p>
<p><img style="display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;" src="https://cultiv.nl/media/2646/newdatabase_496x175.jpg" alt="newdatabase" width="496" height="175" /></p>
<p> </p>
<p>I tend to mumble a little, I'll work on that for future screencasts (also, I didn't shave, sorry). ;-)</p>
<p>Hopefully this will help some people setting up their Umbraco install manually.</p>
<p style="text-align: center;"><object width="550" height="437" data="https://www.youtube.com/v/DP4dwzbL8JY&amp;hl=en_US&amp;fs=1" type="application/x-shockwave-flash" style="display: none !important;"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="https://www.youtube.com/v/DP4dwzbL8JY&amp;hl=en_US&amp;fs=1" /><param name="allowfullscreen" value="true" /></object></p>
<div class="flc-panel" style="width: 550px; height: 437px; top: auto; left: auto; display: block !important;"></div>
<div class="flc-panel" style="width: 550px; height: 437px; top: auto; left: auto; display: block !important;"></div>]]>
                </content:encoded>
            </item>
            <item>
                <title>Dropbox as a Git central repository</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/dropbox-as-a-git-central-repository/</link>
                <pubDate>Sun, 03 Jan 2010 15:14:34 GMT</pubDate>
                <guid>https://cultiv.nl/blog/dropbox-as-a-git-central-repository/</guid>
                <description>
                    <![CDATA[<p>If you've been reading my blog, it should be clear by now that I'm a bit of a fan of the Git version control system.</p>
<p>I've been hosting some projects on Unfuddle for a while now, but have not been very happy with fiddling with SSH keys and setting up the central repositories through the Git Extensions for Windows. It works, but that's all I can say.</p>
<p>Another issue I was not looking forward to tackling was setting up TeamCity to pull from Unfuddle. I haven't tried, and for all I know it might work great, but if there's a perfectly good shortcut that I can take, I'll take it!</p>
<p>A few days ago I saw some tweets from people mentioning Git and DropBox as a combo. Unfortunately, I can't find the messages any more as Twitter's retention policy seems to be very aggressive. So I decided to try doing it myself.</p>
<p>The advantages of having a Git repository in DropBox are that:</p>
<ul>
<li>it does not rely on a service that (for all I know) might go out of business one day;</li>
<li>it prevents me from having to create SSH keys as credentials;</li>
<li>it makes it easier to point TeamCity to a central git repository (which is in fact on the local disk);</li>
<li>the central repository is always synced to all of my dev machines and to the DropBox server, so there is multiple backups in case of catastrophic failure;</li>
<li>you will always have the ability to push changes to a central repository, even if you have no (or intermittent) internet connectivity;</li>
<li>if you have to work without internet connectivity, but with network connectivity, you could just set-up a network share and push and pull to each of the repositories that way.</li>
</ul>
<p>I'm wildly enthusiastic about the distributed nature of the Git version control system, it really does allow me to work from anywhere and in any way that I want.</p>
<h2>Setting up Git with DropBox on Windows</h2>
<p>I am assuming that you have DropBox installed and that you are using the Git Extensions that I've mentioned in earlier blog posts on Git.</p>
<p>I've created a folder somewhere in my DropBox folders that will hold my Git repositories. In there, I've created a folder called "Example.git".</p>
<p>Next, I created a new Git repository using the Git Extensions. When you start Git Extensions, choose "Initialize new repository" from the "Commands" menu.</p>
<p>I created a "Central repository, no working dir" in the "Example.git" folder.</p>
<p><img src="https://cultiv.nl/media/2553/gitdropbox01_491x125.jpg" alt="gitdropbox01" width="491" height="125" /></p>
<p>Then, in the folder that holds my Example project, I created a personal repository, as I would do normally when putting you project under version control (again through "Commands", "Initialize new repository").</p>
<p><img src="https://cultiv.nl/media/2558/gitdropbox02_491x125.jpg" alt="gitdropbox02" width="491" height="125" /></p>
<p>This will open up the repository in Git Extensions. The first thing I like to do is hit the "Edit .gitignore" button, add the default ignores and commit that as the initial commit.</p>
<p><img src="https://cultiv.nl/media/2563/gitdropbox03_500x358.jpg" alt="gitdropbox03" width="500" height="358" /></p>
<p>With that inital commit out of the way, I will add a remote from the "Remotes" menu.</p>
<p>I've name the new remote "DropBoxExample" and instead of entering a URL, I point to the "Examples.git" folder that I created earlier.</p>
<p><img src="https://cultiv.nl/media/2568/gitdropbox04_500x188.jpg" alt="gitdropbox04" width="500" height="188" /></p>
<p>After clicking the "Save" button, Git Extensions will ask if I want to automatically configure the default push and pull behavior, I've skipped this step because the folder on the disk is not actually a server that understands commands. Then I closed the "Remote repositories" window and start pushing the master branch to the remote.</p>
<p><img src="https://cultiv.nl/media/2573/gitdropbox05_499x274.jpg" alt="gitdropbox05" width="499" height="274" /></p>
<p>And got a confirmation message, it worked!</p>
<p><img src="https://cultiv.nl/media/2578/gitdropbox06_500x233.jpg" alt="gitdropbox06" width="500" height="233" /></p>
<p>Now I am able to actually set the pull defaults, so I go back to managing the remote, go to the "Default pull behavior" tab to choose the defaults from the dropdown lists and clicked "Save".</p>
<p><img src="https://cultiv.nl/media/2583/gitdropbox07_498x355.jpg" alt="gitdropbox07" width="498" height="355" /></p>
<p>All done!</p>
<p>I went to my other machine and created the same "D:\Dev\Example" folder.</p>
<p>I opened up Git extensions and initalized the folder as a personal repository. Then I was able to add the remote repository in exactly the same way, instead of entering a URL, I pointed to the "Example.git" folder in DropBox, saved the remote and pulled from it.</p>
<p>To my delight, I saw the .gitignore file appear immediately and noticed that I had received the commit history from the other machine. Success!</p>
<p>Of course I then proceeded to add a Visual Studio project, pushed it to the central repository, pulled it in on the other machine, and again, everything appeared as I hoped it would. Success!</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>If you've been reading my blog, it should be clear by now that I'm a bit of a fan of the Git version control system.</p>
<p>I've been hosting some projects on Unfuddle for a while now, but have not been very happy with fiddling with SSH keys and setting up the central repositories through the Git Extensions for Windows. It works, but that's all I can say.</p>
<p>Another issue I was not looking forward to tackling was setting up TeamCity to pull from Unfuddle. I haven't tried, and for all I know it might work great, but if there's a perfectly good shortcut that I can take, I'll take it!</p>
<p>A few days ago I saw some tweets from people mentioning Git and DropBox as a combo. Unfortunately, I can't find the messages any more as Twitter's retention policy seems to be very aggressive. So I decided to try doing it myself.</p>
<p>The advantages of having a Git repository in DropBox are that:</p>
<ul>
<li>it does not rely on a service that (for all I know) might go out of business one day;</li>
<li>it prevents me from having to create SSH keys as credentials;</li>
<li>it makes it easier to point TeamCity to a central git repository (which is in fact on the local disk);</li>
<li>the central repository is always synced to all of my dev machines and to the DropBox server, so there is multiple backups in case of catastrophic failure;</li>
<li>you will always have the ability to push changes to a central repository, even if you have no (or intermittent) internet connectivity;</li>
<li>if you have to work without internet connectivity, but with network connectivity, you could just set-up a network share and push and pull to each of the repositories that way.</li>
</ul>
<p>I'm wildly enthusiastic about the distributed nature of the Git version control system, it really does allow me to work from anywhere and in any way that I want.</p>
<h2>Setting up Git with DropBox on Windows</h2>
<p>I am assuming that you have DropBox installed and that you are using the Git Extensions that I've mentioned in earlier blog posts on Git.</p>
<p>I've created a folder somewhere in my DropBox folders that will hold my Git repositories. In there, I've created a folder called "Example.git".</p>
<p>Next, I created a new Git repository using the Git Extensions. When you start Git Extensions, choose "Initialize new repository" from the "Commands" menu.</p>
<p>I created a "Central repository, no working dir" in the "Example.git" folder.</p>
<p><img src="https://cultiv.nl/media/2553/gitdropbox01_491x125.jpg" alt="gitdropbox01" width="491" height="125" /></p>
<p>Then, in the folder that holds my Example project, I created a personal repository, as I would do normally when putting you project under version control (again through "Commands", "Initialize new repository").</p>
<p><img src="https://cultiv.nl/media/2558/gitdropbox02_491x125.jpg" alt="gitdropbox02" width="491" height="125" /></p>
<p>This will open up the repository in Git Extensions. The first thing I like to do is hit the "Edit .gitignore" button, add the default ignores and commit that as the initial commit.</p>
<p><img src="https://cultiv.nl/media/2563/gitdropbox03_500x358.jpg" alt="gitdropbox03" width="500" height="358" /></p>
<p>With that inital commit out of the way, I will add a remote from the "Remotes" menu.</p>
<p>I've name the new remote "DropBoxExample" and instead of entering a URL, I point to the "Examples.git" folder that I created earlier.</p>
<p><img src="https://cultiv.nl/media/2568/gitdropbox04_500x188.jpg" alt="gitdropbox04" width="500" height="188" /></p>
<p>After clicking the "Save" button, Git Extensions will ask if I want to automatically configure the default push and pull behavior, I've skipped this step because the folder on the disk is not actually a server that understands commands. Then I closed the "Remote repositories" window and start pushing the master branch to the remote.</p>
<p><img src="https://cultiv.nl/media/2573/gitdropbox05_499x274.jpg" alt="gitdropbox05" width="499" height="274" /></p>
<p>And got a confirmation message, it worked!</p>
<p><img src="https://cultiv.nl/media/2578/gitdropbox06_500x233.jpg" alt="gitdropbox06" width="500" height="233" /></p>
<p>Now I am able to actually set the pull defaults, so I go back to managing the remote, go to the "Default pull behavior" tab to choose the defaults from the dropdown lists and clicked "Save".</p>
<p><img src="https://cultiv.nl/media/2583/gitdropbox07_498x355.jpg" alt="gitdropbox07" width="498" height="355" /></p>
<p>All done!</p>
<p>I went to my other machine and created the same "D:\Dev\Example" folder.</p>
<p>I opened up Git extensions and initalized the folder as a personal repository. Then I was able to add the remote repository in exactly the same way, instead of entering a URL, I pointed to the "Example.git" folder in DropBox, saved the remote and pulled from it.</p>
<p>To my delight, I saw the .gitignore file appear immediately and noticed that I had received the commit history from the other machine. Success!</p>
<p>Of course I then proceeded to add a Visual Studio project, pushed it to the central repository, pulled it in on the other machine, and again, everything appeared as I hoped it would. Success!</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>A basic backup strategy</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/a-basic-backup-strategy/</link>
                <pubDate>Wed, 30 Dec 2009 16:35:56 GMT</pubDate>
                <guid>https://cultiv.nl/blog/a-basic-backup-strategy/</guid>
                <description>
                    <![CDATA[<p>I'm running a very simple web server for Cultiv and some other projects. It's a virtual server to which I have full remote desktop access. This means that I am the administrator and I decide what goes on at the server, no interference by my hosting provider. But, as always, with great power comes great responsibility&hellip;</p>
<p>I believe my hosting provider makes a backup of the whole server every night, and at best, I can have them restore a 1-day old backup. One day of retention is not something that I feel comfortable to rely on, by far!</p>
<p>Recently Jeff Attwood (of Coding Horror and StackOverflow fame) had a big <a href="http://www.codinghorror.comhttps://cultiv.nl/blog/archives/001315.html">scare</a> and the resulting discussion that followed, lead to a blog post by Joel Spolsky (of FogCreek and StackOverflow fame) pointing out that <a href="http://www.joelonsoftware.com/items/2009/12/14.html">backing up is not the problem</a>, restoring usually is.</p>
<p>Well, since I had NO backup strategy, whatsoever, I figured it was about time to change that.</p>
<p>My current server specs are: A Windows Server Web - (2008 Hyper-V VPS) with IIS7 and Microsoft SQL Express server. It's that simple!</p>
<h2>What to backup?</h2>
<p>The question of what to backup seems like a simple one to me:</p>
<ul>
<li>my websites (including file/folder permissions);</li>
<li>the website's MS SQL databases;</li>
<li>the IIS configuration for the websites;</li>
<li>the IIS log files, so that I could maybe reconstruct what happened in case of a catastrophe.</li>
</ul>
<h2>How to backup?</h2>
<h3>Websites and meta content</h3>
<p>The websites are all in one folder, so that's easy (I'll talk about the permissions later).</p>
<p>I had to look a little bit to find a way to backup the configuration files, but a post about <a href="http://learn.iis.net/page.aspx/129/using-iis-70-configuration-history/"> IIS configuration history</a> was a great resource.</p>
<p>To backup the current IIS configuration, I included the %windir%\system32\inetsrv\config\ folder and I love that the configuration changes are being written automatically to the %systemdrive%\inetpub\history directory. That way, I could recover and older configuration if needed, cool!</p>
<p>Finally, I included the %systemdrive%\inetpub\logs file for the sake of it.</p>
<h3>SQL Express</h3>
<p>At first, I was backing up SQL's ".mdf" and ".ldf" files, which is an utterly stupid idea, as I learned from <a href="http://blog.stackoverflow.com/2009/12/podcast-78/">StackOverflow postcast 78</a>. So I needed a different strategy for that. SQL Express doesn't offer the ability to create automated back-ups, so I had to look for extra software. This was difficult, nothing really did what I wanted it to do: give me a bunch of .bak files. Everything I found was either too fancy or didn't work.</p>
<p>My colleague pointed me in the direction of an article on <a href="http://serverfault.com/questions/4542/sql-server-2008-express-best-backup-solution"> ServerFault</a> and I was able to construct a decent enough solution out of this.</p>
<p>I took the SQL script in the ServerFault post and modified it a little, now the backup files are zipped using 7zip instead of zip and at maximum compression ratio (7zip can compress text really, really well, so why not). I put it in the folder C:\DatabaseBackup as per the default for the script.</p>
<p>Next, I set up a scheduled task in Windows, to run the script every day. The action is "Start a program", the program/script is "sqlcmd" and the arguments are:<br /> -i C:\DatabaseBackup\backup.sql -o C:\DatabaseBackup\output.txt -S .\SQLEXPRESS<br /> Where .\SQLEXPRESS is the name of my (you guessed it) SQL Express server. You might need to do add some login credentials to these arguments, have a look at the <a href="http://msdn.microsoft.com/en-us/library/ms162773.aspx">sqlcmd documentation</a> for the details.</p>
<p>Finally, before running the script for the first time, I had to enable the <a href="http://msdn.microsoft.com/en-us/library/ms190693.aspx">xp_cmdshell option</a> in SQL Express. Make sure to read up on the security implications when you do so.</p>
<p>Now, this will not give you any notifications when the SQL script is unable to backup the databases. On another server, I installed <a href="http://www.valesoftware.com/products-express-agent.php">Vale Express Agent</a> to get notifications when the SQL fails. To do this, make sure to paste the SQL directly into a new backup job (don't use sqlcmd to call the script!).</p>
<h2>Where and how to backup?</h2>
<p>I've been working with <a href="http://aws.amazon.com/s3/">Amazon S3</a> lately and S3 was also mentioned in the <a href="http://blog.stackoverflow.com/2009/12/podcast-78/">podcast</a> that I mentioned earlier. Basically, Amazon makes sure that your data is in at least two locations in the world at all times. Also, S3 is terribly inexpensive, so it seemed like a good idea to backup to their servers.</p>
<p>Enter JungleDisk. I'd heard about JungleDisk before, it can backup all of my data to S3 and it is dirt cheap. It's only $5 a month for a <a href="https://www.jungledisk.com/business/">server edition</a> (which runs the backup as a Windows service), this includes the first 10 GB of storage for free! Great deal, as I currently only have a few hunder megabytes to backup anyway.</p>
<p>JungleDisk also natively supports backing up NTFS file permissions, which is exactly what I need.</p>
<p>Setting up was quite easy, however I was suddenly stuck in a "<em>looking for server</em>" screen after entering my JungleDisk credentials. As it turns out, the first time you set up the software, you have to start "<em>Set License Key for Jungle Disk Server Edition</em>" first. After that, it was easy to add the folders I needed and exclude .mdf/.ldf files.</p>
<h2>How to restore?</h2>
<p>Apparently, this is the most important part of my backup strategy&hellip; And I'm being dumb about it, because I haven't tried restoring at all. I mean, yes, I've restored a JungleDisk backup to see if I can get my files back, but that's it.</p>
<p>I am prepared to spend a few hours rebuilding my server if something happens to it. Currently I don't have much data and a simple deployment strategy, so this should not be a big problem.</p>
<p>I'll revisit the restore part once I have to move to a much bigger server, but by then, I'll probably also have to revisit the backup strategy. As I said, it's basic.</p>
<blockquote>
<p>10 PRINT "REALLY BASIC"</p>
<p>20 GOTO 10</p>
<p>RUN</p>
</blockquote>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>I'm running a very simple web server for Cultiv and some other projects. It's a virtual server to which I have full remote desktop access. This means that I am the administrator and I decide what goes on at the server, no interference by my hosting provider. But, as always, with great power comes great responsibility&hellip;</p>
<p>I believe my hosting provider makes a backup of the whole server every night, and at best, I can have them restore a 1-day old backup. One day of retention is not something that I feel comfortable to rely on, by far!</p>
<p>Recently Jeff Attwood (of Coding Horror and StackOverflow fame) had a big <a href="http://www.codinghorror.comhttps://cultiv.nl/blog/archives/001315.html">scare</a> and the resulting discussion that followed, lead to a blog post by Joel Spolsky (of FogCreek and StackOverflow fame) pointing out that <a href="http://www.joelonsoftware.com/items/2009/12/14.html">backing up is not the problem</a>, restoring usually is.</p>
<p>Well, since I had NO backup strategy, whatsoever, I figured it was about time to change that.</p>
<p>My current server specs are: A Windows Server Web - (2008 Hyper-V VPS) with IIS7 and Microsoft SQL Express server. It's that simple!</p>
<h2>What to backup?</h2>
<p>The question of what to backup seems like a simple one to me:</p>
<ul>
<li>my websites (including file/folder permissions);</li>
<li>the website's MS SQL databases;</li>
<li>the IIS configuration for the websites;</li>
<li>the IIS log files, so that I could maybe reconstruct what happened in case of a catastrophe.</li>
</ul>
<h2>How to backup?</h2>
<h3>Websites and meta content</h3>
<p>The websites are all in one folder, so that's easy (I'll talk about the permissions later).</p>
<p>I had to look a little bit to find a way to backup the configuration files, but a post about <a href="http://learn.iis.net/page.aspx/129/using-iis-70-configuration-history/"> IIS configuration history</a> was a great resource.</p>
<p>To backup the current IIS configuration, I included the %windir%\system32\inetsrv\config\ folder and I love that the configuration changes are being written automatically to the %systemdrive%\inetpub\history directory. That way, I could recover and older configuration if needed, cool!</p>
<p>Finally, I included the %systemdrive%\inetpub\logs file for the sake of it.</p>
<h3>SQL Express</h3>
<p>At first, I was backing up SQL's ".mdf" and ".ldf" files, which is an utterly stupid idea, as I learned from <a href="http://blog.stackoverflow.com/2009/12/podcast-78/">StackOverflow postcast 78</a>. So I needed a different strategy for that. SQL Express doesn't offer the ability to create automated back-ups, so I had to look for extra software. This was difficult, nothing really did what I wanted it to do: give me a bunch of .bak files. Everything I found was either too fancy or didn't work.</p>
<p>My colleague pointed me in the direction of an article on <a href="http://serverfault.com/questions/4542/sql-server-2008-express-best-backup-solution"> ServerFault</a> and I was able to construct a decent enough solution out of this.</p>
<p>I took the SQL script in the ServerFault post and modified it a little, now the backup files are zipped using 7zip instead of zip and at maximum compression ratio (7zip can compress text really, really well, so why not). I put it in the folder C:\DatabaseBackup as per the default for the script.</p>
<p>Next, I set up a scheduled task in Windows, to run the script every day. The action is "Start a program", the program/script is "sqlcmd" and the arguments are:<br /> -i C:\DatabaseBackup\backup.sql -o C:\DatabaseBackup\output.txt -S .\SQLEXPRESS<br /> Where .\SQLEXPRESS is the name of my (you guessed it) SQL Express server. You might need to do add some login credentials to these arguments, have a look at the <a href="http://msdn.microsoft.com/en-us/library/ms162773.aspx">sqlcmd documentation</a> for the details.</p>
<p>Finally, before running the script for the first time, I had to enable the <a href="http://msdn.microsoft.com/en-us/library/ms190693.aspx">xp_cmdshell option</a> in SQL Express. Make sure to read up on the security implications when you do so.</p>
<p>Now, this will not give you any notifications when the SQL script is unable to backup the databases. On another server, I installed <a href="http://www.valesoftware.com/products-express-agent.php">Vale Express Agent</a> to get notifications when the SQL fails. To do this, make sure to paste the SQL directly into a new backup job (don't use sqlcmd to call the script!).</p>
<h2>Where and how to backup?</h2>
<p>I've been working with <a href="http://aws.amazon.com/s3/">Amazon S3</a> lately and S3 was also mentioned in the <a href="http://blog.stackoverflow.com/2009/12/podcast-78/">podcast</a> that I mentioned earlier. Basically, Amazon makes sure that your data is in at least two locations in the world at all times. Also, S3 is terribly inexpensive, so it seemed like a good idea to backup to their servers.</p>
<p>Enter JungleDisk. I'd heard about JungleDisk before, it can backup all of my data to S3 and it is dirt cheap. It's only $5 a month for a <a href="https://www.jungledisk.com/business/">server edition</a> (which runs the backup as a Windows service), this includes the first 10 GB of storage for free! Great deal, as I currently only have a few hunder megabytes to backup anyway.</p>
<p>JungleDisk also natively supports backing up NTFS file permissions, which is exactly what I need.</p>
<p>Setting up was quite easy, however I was suddenly stuck in a "<em>looking for server</em>" screen after entering my JungleDisk credentials. As it turns out, the first time you set up the software, you have to start "<em>Set License Key for Jungle Disk Server Edition</em>" first. After that, it was easy to add the folders I needed and exclude .mdf/.ldf files.</p>
<h2>How to restore?</h2>
<p>Apparently, this is the most important part of my backup strategy&hellip; And I'm being dumb about it, because I haven't tried restoring at all. I mean, yes, I've restored a JungleDisk backup to see if I can get my files back, but that's it.</p>
<p>I am prepared to spend a few hours rebuilding my server if something happens to it. Currently I don't have much data and a simple deployment strategy, so this should not be a big problem.</p>
<p>I'll revisit the restore part once I have to move to a much bigger server, but by then, I'll probably also have to revisit the backup strategy. As I said, it's basic.</p>
<blockquote>
<p>10 PRINT "REALLY BASIC"</p>
<p>20 GOTO 10</p>
<p>RUN</p>
</blockquote>]]>
                </content:encoded>
            </item>
            <item>
                <title>Released: Media cache package</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/released-media-cache-package/</link>
                <pubDate>Sun, 20 Dec 2009 16:22:42 GMT</pubDate>
                <guid>https://cultiv.nl/blog/released-media-cache-package/</guid>
                <description>
                    <![CDATA[<p>Recently, I've been working on a site that presents 30 to a 120 items from Umbraco's media section in the frontend of the website.</p>
<p>In the past few weeks, I've been tweaking the site for performance and noticed that there were an aweful lot of SQL queries being performed in the database. As it turns out, calls to the umbraco.library:GetMedia() method are being sent directly to the database. This meant that for each media item, three queries are being performed. Times a 120... That starts to hurt a little.</p>
<p>Also, it is impossible for us to turn on caching on this macro completely because updating the media item with a new image would not expire the cache.</p>
<p>I had to come up with something else that would cache calls to the media library. So today, I'm presenting you the <a href="http://our.umbraco.org/projects/cultiv-mediacache">Cultiv MediaCache package</a>.<br /> This package provides an XSLT extension that provides a caching mechanism for calls to the "GetMedia" method.</p>
<p>It's very easy to use:<br /> In your XSLT files, instead of doing calls to <em>umbraco.library:GetMedia()</em>, you do them to <em>Cultiv.MediaCache:GetMedia()</em>.<br /> That's it! Told you it was easy.</p>
<p>Read all about it on <a href="http://our.umbraco.org/projects/cultiv-mediacache">the project page</a>, download it, use it, vote it up. Okay, thanks! :-)</p>
<p><em>Tiny update dec 20, 2009 - 17:28: Now compatible with .net 2.0 installs of Umbraco (previously only worked on .net 3.5).</em></p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Recently, I've been working on a site that presents 30 to a 120 items from Umbraco's media section in the frontend of the website.</p>
<p>In the past few weeks, I've been tweaking the site for performance and noticed that there were an aweful lot of SQL queries being performed in the database. As it turns out, calls to the umbraco.library:GetMedia() method are being sent directly to the database. This meant that for each media item, three queries are being performed. Times a 120... That starts to hurt a little.</p>
<p>Also, it is impossible for us to turn on caching on this macro completely because updating the media item with a new image would not expire the cache.</p>
<p>I had to come up with something else that would cache calls to the media library. So today, I'm presenting you the <a href="http://our.umbraco.org/projects/cultiv-mediacache">Cultiv MediaCache package</a>.<br /> This package provides an XSLT extension that provides a caching mechanism for calls to the "GetMedia" method.</p>
<p>It's very easy to use:<br /> In your XSLT files, instead of doing calls to <em>umbraco.library:GetMedia()</em>, you do them to <em>Cultiv.MediaCache:GetMedia()</em>.<br /> That's it! Told you it was easy.</p>
<p>Read all about it on <a href="http://our.umbraco.org/projects/cultiv-mediacache">the project page</a>, download it, use it, vote it up. Okay, thanks! :-)</p>
<p><em>Tiny update dec 20, 2009 - 17:28: Now compatible with .net 2.0 installs of Umbraco (previously only worked on .net 3.5).</em></p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Version control in Git - Part 3 (a central repository)</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/version-control-in-git-part-3-a-central-repository/</link>
                <pubDate>Tue, 06 Oct 2009 11:54:01 GMT</pubDate>
                <guid>https://cultiv.nl/blog/version-control-in-git-part-3-a-central-repository/</guid>
                <description>
                    <![CDATA[<p>So now that you've <a href="https://cultiv.nl/blog/version-control-in-git-part-1/" title="Version control in Git - Part 1">started</a> <a href="https://cultiv.nl/blog/version-control-in-git-part-2-set-up-and-usage/" title="Version control in Git - Part 2 (set-up and usage)">using</a> Git, you might want to share your repository with your team using a central repository. I'll show an example of how to do that by using a free account at <a href="http://www.unfuddle.com">Unfuddle.com</a>.</p>
<p>Sign up for Unfuddle and log in to your account (through your_account_name.unfuddle.com). Go to "Repositories" and create a new Git repository.</p>
<p>Now you have to create an authorization key, to be able to log in to the Git repository remotely.</p>
<p><span><img src="https://cultiv.nl/media/846/2009-10-05_193837.png" alt="2009-10-05_193837" width="232" height="134" /></span></p>
<p>Go back to Visual Studio and click Git's "Browse repository" (the folder icon) button again. Then in the menu go to "Remotes" &gt; "PuTTY" &gt; "Generate or import key".</p>
<p><img src="https://cultiv.nl/media/906/2009-10-06_120359_499x129.jpg" alt="2009-10-06_120359" width="499" height="129" /></p>
<p>Make sure the settings for generating the key are correct, the key needs to be 2048 bits.</p>
<p><img src="https://cultiv.nl/media/911/2009-10-05_090458.png" alt="2009-10-05_090458" width="483" height="467" /></p>
<p>After you've generated the key, change the key comment to your e-mail address, and enter a passphrase for the key. Now, make sure you copy the key from <strong>this</strong> window! Saving the public key generates a slightly different format, but Unfuddle really needs the format as it is in this window.</p>
<p>Save the public and private key somewhere anyway, you'll especially be needing the private key later.</p>
<p>In Unfuddle go to "People" &gt; and edit the Account admin. In the bottom left you can enter a "New public key...".</p>
<p>When that key is accepted, go back to the "Repositories" tab and find the repository server, under your repository title (something like git@your_account.unfuddle.com:your_account/abr.git), copy this address.</p>
<p>Now you can set up the remote server in Visual Studio. In the menu bar, click "Git" &gt; "Manage remotes". Give your remote server a name (no spaces) and paste the address you just copied.</p>
<p>Browse the private key that you stored earlier and choose hit "Load SSH key". Enter the password for that key and then you can save the connection. For some reason the "test connection" button fails for me ("ERROR:gitosis.serve.main:Need SSH_ORIGINAL_COMMAND in environment."), it still works though.</p>
<p>So now you're ready to push whatever is committed in your current branch to the remote server, use the blue up arrow ("Push changes to remote repository") to do so. You could also then push all branches and tags, or do a pull first to resolve any merge conflicts if you want.</p>
<p>In the next part of this series, I'll give a quick rundown of branching and merging.</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>So now that you've <a href="https://cultiv.nl/blog/version-control-in-git-part-1/" title="Version control in Git - Part 1">started</a> <a href="https://cultiv.nl/blog/version-control-in-git-part-2-set-up-and-usage/" title="Version control in Git - Part 2 (set-up and usage)">using</a> Git, you might want to share your repository with your team using a central repository. I'll show an example of how to do that by using a free account at <a href="http://www.unfuddle.com">Unfuddle.com</a>.</p>
<p>Sign up for Unfuddle and log in to your account (through your_account_name.unfuddle.com). Go to "Repositories" and create a new Git repository.</p>
<p>Now you have to create an authorization key, to be able to log in to the Git repository remotely.</p>
<p><span><img src="https://cultiv.nl/media/846/2009-10-05_193837.png" alt="2009-10-05_193837" width="232" height="134" /></span></p>
<p>Go back to Visual Studio and click Git's "Browse repository" (the folder icon) button again. Then in the menu go to "Remotes" &gt; "PuTTY" &gt; "Generate or import key".</p>
<p><img src="https://cultiv.nl/media/906/2009-10-06_120359_499x129.jpg" alt="2009-10-06_120359" width="499" height="129" /></p>
<p>Make sure the settings for generating the key are correct, the key needs to be 2048 bits.</p>
<p><img src="https://cultiv.nl/media/911/2009-10-05_090458.png" alt="2009-10-05_090458" width="483" height="467" /></p>
<p>After you've generated the key, change the key comment to your e-mail address, and enter a passphrase for the key. Now, make sure you copy the key from <strong>this</strong> window! Saving the public key generates a slightly different format, but Unfuddle really needs the format as it is in this window.</p>
<p>Save the public and private key somewhere anyway, you'll especially be needing the private key later.</p>
<p>In Unfuddle go to "People" &gt; and edit the Account admin. In the bottom left you can enter a "New public key...".</p>
<p>When that key is accepted, go back to the "Repositories" tab and find the repository server, under your repository title (something like git@your_account.unfuddle.com:your_account/abr.git), copy this address.</p>
<p>Now you can set up the remote server in Visual Studio. In the menu bar, click "Git" &gt; "Manage remotes". Give your remote server a name (no spaces) and paste the address you just copied.</p>
<p>Browse the private key that you stored earlier and choose hit "Load SSH key". Enter the password for that key and then you can save the connection. For some reason the "test connection" button fails for me ("ERROR:gitosis.serve.main:Need SSH_ORIGINAL_COMMAND in environment."), it still works though.</p>
<p>So now you're ready to push whatever is committed in your current branch to the remote server, use the blue up arrow ("Push changes to remote repository") to do so. You could also then push all branches and tags, or do a pull first to resolve any merge conflicts if you want.</p>
<p>In the next part of this series, I'll give a quick rundown of branching and merging.</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Version control in Git - Part 2 (set-up and usage)</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/version-control-in-git-part-2-set-up-and-usage/</link>
                <pubDate>Mon, 05 Oct 2009 19:37:49 GMT</pubDate>
                <guid>https://cultiv.nl/blog/version-control-in-git-part-2-set-up-and-usage/</guid>
                <description>
                    <![CDATA[<p>So <a href="https://cultiv.nl/blog/version-control-in-git-part-3-a-central-repository/" title="Version control in Git - Part 2 (set-up and usage)">you're ready to start using Git</a>? Here's how to start:</p>
<p>First of all, go and download and install the <a href="http://code.google.com/p/gitextensions/downloads/list">Git extensions for Windows</a>. The featured (full) release is recommended.</p>
<p>In Visual Studio, you'll now see a few new buttons (in Windows Explorer, there's also some new context items that will show up when you right-click a folder).</p>
<p><img src="https://cultiv.nl/media/846/2009-10-05_193837.png" alt="2009-10-05_193837" width="232" height="134" /></p>
<p>As you can see it's a tiny toolbar, click the last icon (settings), you have to set a name and e-mail address, they will be attached to any commit you do.</p>
<p><img src="https://cultiv.nl/media/851/2009-10-05_194927_499x288.jpg" alt="2009-10-05_194927" width="499" height="288" /></p>
<p>I've noticed that in order for the toolbar buttons to work, I have to open a file in the solution. So just open one of the files and make sure the cursor is in the file somewhere.</p>
<p>Hit "Ok" and click on the folder icon ("Browse repository"). You'll be presented with a screen with three options, one of which is "Initialize repository".</p>
<p><img src="https://cultiv.nl/media/856/2009-10-06_111854_498x375.jpg" alt="2009-10-06_111854" width="498" height="375" /></p>
<p>Initialize the repository in the root directory of your solution, this is typically where your .sln file is. The content in this folder and everything in the subfolders will be under source control. This is also your personal repository, there is not even a central repository yet.</p>
<p>The repository is simply one .git folder in the solution folder.</p>
<p><img src="https://cultiv.nl/media/861/2009-10-06_111310_500x153.jpg" alt="2009-10-06_111310" width="500" height="153" /></p>
<p>Almost done!</p>
<p><img src="https://cultiv.nl/media/866/2009-10-06_111022_498x375.jpg" alt="2009-10-06_111022" width="498" height="375" /></p>
<p>You're ready to commit your project to the repository. First, make sure you ignore the appropriate files, hit the "edit .gitignore" button and add the default ignores. For me personally, this is all that I need, you might want to tweak it.</p>
<p>Ready. Now you can do your first commit! You can skip the "Add files" button, this will just stage all the files for a commit, you can also do this in the commit screen.</p>
<p><img src="https://cultiv.nl/media/871/2009-10-06_113925_498x375.jpg" alt="2009-10-06_113925" width="498" height="375" /></p>
<p>Select all of the files and click "Stage selected files", type a commit message and click "Commit".</p>
<p>This creates the first branche, called master. You're good to go code and make changes. When you're ready to commit again, just use the tiny toolbar button instead of the repository browser.</p>
<p><img style="outline-width: 0px; outline-style: initial; outline-color: initial; font-size: 15px; vertical-align: baseline; background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; padding: 0px; margin: 0px; border: 0px initial initial;" src="https://cultiv.nl/media/846/2009-10-05_193837.png" alt="2009-10-05_193837" width="232" height="134" /></p>
<p>In the next part of this series, I'll show how to commit the changes to a remote repository using Unfuddle.com.</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>So <a href="https://cultiv.nl/blog/version-control-in-git-part-3-a-central-repository/" title="Version control in Git - Part 2 (set-up and usage)">you're ready to start using Git</a>? Here's how to start:</p>
<p>First of all, go and download and install the <a href="http://code.google.com/p/gitextensions/downloads/list">Git extensions for Windows</a>. The featured (full) release is recommended.</p>
<p>In Visual Studio, you'll now see a few new buttons (in Windows Explorer, there's also some new context items that will show up when you right-click a folder).</p>
<p><img src="https://cultiv.nl/media/846/2009-10-05_193837.png" alt="2009-10-05_193837" width="232" height="134" /></p>
<p>As you can see it's a tiny toolbar, click the last icon (settings), you have to set a name and e-mail address, they will be attached to any commit you do.</p>
<p><img src="https://cultiv.nl/media/851/2009-10-05_194927_499x288.jpg" alt="2009-10-05_194927" width="499" height="288" /></p>
<p>I've noticed that in order for the toolbar buttons to work, I have to open a file in the solution. So just open one of the files and make sure the cursor is in the file somewhere.</p>
<p>Hit "Ok" and click on the folder icon ("Browse repository"). You'll be presented with a screen with three options, one of which is "Initialize repository".</p>
<p><img src="https://cultiv.nl/media/856/2009-10-06_111854_498x375.jpg" alt="2009-10-06_111854" width="498" height="375" /></p>
<p>Initialize the repository in the root directory of your solution, this is typically where your .sln file is. The content in this folder and everything in the subfolders will be under source control. This is also your personal repository, there is not even a central repository yet.</p>
<p>The repository is simply one .git folder in the solution folder.</p>
<p><img src="https://cultiv.nl/media/861/2009-10-06_111310_500x153.jpg" alt="2009-10-06_111310" width="500" height="153" /></p>
<p>Almost done!</p>
<p><img src="https://cultiv.nl/media/866/2009-10-06_111022_498x375.jpg" alt="2009-10-06_111022" width="498" height="375" /></p>
<p>You're ready to commit your project to the repository. First, make sure you ignore the appropriate files, hit the "edit .gitignore" button and add the default ignores. For me personally, this is all that I need, you might want to tweak it.</p>
<p>Ready. Now you can do your first commit! You can skip the "Add files" button, this will just stage all the files for a commit, you can also do this in the commit screen.</p>
<p><img src="https://cultiv.nl/media/871/2009-10-06_113925_498x375.jpg" alt="2009-10-06_113925" width="498" height="375" /></p>
<p>Select all of the files and click "Stage selected files", type a commit message and click "Commit".</p>
<p>This creates the first branche, called master. You're good to go code and make changes. When you're ready to commit again, just use the tiny toolbar button instead of the repository browser.</p>
<p><img style="outline-width: 0px; outline-style: initial; outline-color: initial; font-size: 15px; vertical-align: baseline; background-image: initial; background-repeat: initial; background-attachment: initial; -webkit-background-clip: initial; -webkit-background-origin: initial; background-color: transparent; background-position: initial initial; padding: 0px; margin: 0px; border: 0px initial initial;" src="https://cultiv.nl/media/846/2009-10-05_193837.png" alt="2009-10-05_193837" width="232" height="134" /></p>
<p>In the next part of this series, I'll show how to commit the changes to a remote repository using Unfuddle.com.</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Version control in Git - Part 1</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/version-control-in-git-part-1/</link>
                <pubDate>Sat, 03 Oct 2009 17:04:02 GMT</pubDate>
                <guid>https://cultiv.nl/blog/version-control-in-git-part-1/</guid>
                <description>
                    <![CDATA[<p>Version control systems are evil. They hate me and are out to get me. I can't count the number of ways that I've been bitten by SourceSafe (safe.. ha! get it?), CVS, SVN and TFS.</p>
<p>Enter Git, my saviour. For now. I have literally worked with Git for three days, so I know very little and I can't claim that it will be any better than the rest of them, but it sure seems like a great system and I've seen very good reviews online.</p>
<p><strong>Advantages</strong></p>
<p>Working with Git, as opposed to other source control systems has some key advantages.</p>
<p>Git is great for experimental projects, where you want to give your developers the power to experiment wildly without any of their experiments getting into the source control system if they don't work out. Making a new branch in Git is easy, merging the branch back is quick and simple. Git just gets out of your way and does the hard work for you.<br /> Of course you could still have merge conflicts sometimes, and they need to be resolved by hand, but at least you can trust the rest of the merge to go well (unlike the horrors I've seen in CVS and SVN).</p>
<p>One of the things that I really like is that Git only creates one folder in your source code file structure and not one folder for each directory (like CVS/SVN). Git also does not require all your files to be read-only, like in TFS. And finally, you can just move/delete files without all kinds of errors popping up, Git just detects the move or deletion.</p>
<p>I have a local repository of all of the files and history my project, I can commit frequently to the local repository and when I am satisfied about my work, I could send it to a remote, central repository. Having a distributed repository also means that I am never tied to a network/internet connection to use source control.<br /> Also, when the central repository is down, I could just find a team member that has a recent copy and pull down their repository while I wait for the central server to be fixed.</p>
<p>Using the <a href="http://code.google.com/p/gitextensions/">Git Extensions for Windows</a> gave me another nice little productivity nugget: a sensible and (as far as I can tell) complete list of files that need to be ignored while committing changes. Everything from "Thumbs.db" to the Resharper folders is in there, cool.</p>
<p>As I understand it, Git also works great with large sets of files and large teams. The Linux kernel is under Git source control and that's a lot of files and a lot of collaboration.</p>
<p>There are plenty more features that are cool like cherry-picking commits, the built in CVS proxy server, octopus merging, etcetera. If you want to read more, go and have a look at the <a href="http://en.wikipedia.org/wiki/Git_(software)">Git Wikipedia article</a>. There are some great <a href="http://video.google.nl/videosearch?q=git">video's on YouTube</a> as well if you want to understand Git better. Remember that on the Windows side, you don't even need to know the command line syntax.</p>
<p><strong>Disadvantages</strong></p>
<p>I really haven't found any disadvantages yet to using Git. Sure, it's a new system and there's a few things to learn, but that's about it. I've only spent about a day understanding Git and I feel very comfortable already.</p>
<p>Of course, once I start using it more often and in a team scenario, I might run into some difficulties, we'll see.</p>
<p>In the next post, I'll show how easy Git is to set-up and use in Windows with Visual Studio (again, unlike for example SVN).</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Version control systems are evil. They hate me and are out to get me. I can't count the number of ways that I've been bitten by SourceSafe (safe.. ha! get it?), CVS, SVN and TFS.</p>
<p>Enter Git, my saviour. For now. I have literally worked with Git for three days, so I know very little and I can't claim that it will be any better than the rest of them, but it sure seems like a great system and I've seen very good reviews online.</p>
<p><strong>Advantages</strong></p>
<p>Working with Git, as opposed to other source control systems has some key advantages.</p>
<p>Git is great for experimental projects, where you want to give your developers the power to experiment wildly without any of their experiments getting into the source control system if they don't work out. Making a new branch in Git is easy, merging the branch back is quick and simple. Git just gets out of your way and does the hard work for you.<br /> Of course you could still have merge conflicts sometimes, and they need to be resolved by hand, but at least you can trust the rest of the merge to go well (unlike the horrors I've seen in CVS and SVN).</p>
<p>One of the things that I really like is that Git only creates one folder in your source code file structure and not one folder for each directory (like CVS/SVN). Git also does not require all your files to be read-only, like in TFS. And finally, you can just move/delete files without all kinds of errors popping up, Git just detects the move or deletion.</p>
<p>I have a local repository of all of the files and history my project, I can commit frequently to the local repository and when I am satisfied about my work, I could send it to a remote, central repository. Having a distributed repository also means that I am never tied to a network/internet connection to use source control.<br /> Also, when the central repository is down, I could just find a team member that has a recent copy and pull down their repository while I wait for the central server to be fixed.</p>
<p>Using the <a href="http://code.google.com/p/gitextensions/">Git Extensions for Windows</a> gave me another nice little productivity nugget: a sensible and (as far as I can tell) complete list of files that need to be ignored while committing changes. Everything from "Thumbs.db" to the Resharper folders is in there, cool.</p>
<p>As I understand it, Git also works great with large sets of files and large teams. The Linux kernel is under Git source control and that's a lot of files and a lot of collaboration.</p>
<p>There are plenty more features that are cool like cherry-picking commits, the built in CVS proxy server, octopus merging, etcetera. If you want to read more, go and have a look at the <a href="http://en.wikipedia.org/wiki/Git_(software)">Git Wikipedia article</a>. There are some great <a href="http://video.google.nl/videosearch?q=git">video's on YouTube</a> as well if you want to understand Git better. Remember that on the Windows side, you don't even need to know the command line syntax.</p>
<p><strong>Disadvantages</strong></p>
<p>I really haven't found any disadvantages yet to using Git. Sure, it's a new system and there's a few things to learn, but that's about it. I've only spent about a day understanding Git and I feel very comfortable already.</p>
<p>Of course, once I start using it more often and in a team scenario, I might run into some difficulties, we'll see.</p>
<p>In the next post, I'll show how easy Git is to set-up and use in Windows with Visual Studio (again, unlike for example SVN).</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Umbraco tip of the week: &quot;Folder&quot; is not a good name for a documentType</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/umbraco-tip-of-the-week-folder-is-not-a-good-name-for-a-documenttype/</link>
                <pubDate>Sun, 06 Sep 2009 14:33:16 GMT</pubDate>
                <guid>https://cultiv.nl/blog/umbraco-tip-of-the-week-folder-is-not-a-good-name-for-a-documenttype/</guid>
                <description>
                    <![CDATA[<p>This is a really short tip: Don't create a new documentType with the alias "Folder". This alias has already been used by folders in the media section.</p>
<p>In normal day-to-day use this is not a problem, but it becomes one when you try to programatically access the documentType by alias (DocumentType.GetByAlias("Folder")). I ran into this problem the other day and couldn't figure out why I was getting unexpected results until I had a look at what the ID actually represented, a media folder.</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>This is a really short tip: Don't create a new documentType with the alias "Folder". This alias has already been used by folders in the media section.</p>
<p>In normal day-to-day use this is not a problem, but it becomes one when you try to programatically access the documentType by alias (DocumentType.GetByAlias("Folder")). I ran into this problem the other day and couldn't figure out why I was getting unexpected results until I had a look at what the ID actually represented, a media folder.</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Styling the ASP.NET login controls</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/styling-the-aspnet-login-controls/</link>
                <pubDate>Mon, 27 Jul 2009 19:34:36 GMT</pubDate>
                <guid>https://cultiv.nl/blog/styling-the-aspnet-login-controls/</guid>
                <description>
                    <![CDATA[<p>Today, I was handed a piece of HTML which featured a login form. My assignment: create this in Umbraco, using the default Membership provider.</p>
<p>This could be considered as an "Umbraco tip of the week", however this applies to ASP.NET webforms in general as well.</p>
<p>I thought about applying styles and maybe some Javascript hacking to make the login form look exactly like the design. Then, after some searching on the internet, I found out that it is actually extremely easy to apply any layout to your login form.</p>
<p>I started out with this:</p>
<pre class="brush: xml">&lt;form runat="server"&gt;<br />
&lt;asp:Login id="Login1" runat="server" /&gt;<br />
&lt;/form&gt;<br />
</pre>
<p>The designer had made some prettier input boxes with background images and the "Login" button was actually style link.</p>
<p>You can actually use something called a LayoutTemplate from<br /> within your login control.</p>
<p>The easiest way to do this is to:</p>
<ul>
<li>Open up your master page in Visual Studio</li>
<li>Go to the designer view Right-click the Login control and choose "Convert to template"</li>
<li>Start customizing the HTML</li>
</ul>
<p>However, if you want to do this manually (and who doesn't <strong>love</strong> some manual tinkering), you have to keep in mind that you need to put at least three controls in your login control:</p>
<ul>
<li>An asp:TextBox control* with an ID of: UserName</li>
<li>An asp:TextBox control* with an ID of: Password</li>
<li>Either an asp:Button an asp:ImageButton or an asp:LinkButton control with a property: CommandName="Login"</li>
</ul>
<p><em>* When I say a TextBox control, I actually mean a web control that implements ITextControl.</em></p>
<p>If you want to show an error when the login fails, add an asp:Literal with an ID of: FailureText</p>
<p>In the end, you'll end up with a piece of code that looks a bit like this (<strong>custom styling removed to keep this nice and short</strong>):</p>
<pre class="brush: xml">&lt;form runat="server"&gt;<br />
&lt;asp:Login id="Login1" runat="server"&gt;<br />
&lt;LayoutTemplate&gt;<br />
&lt;asp:TextBox ID="UserName" runat="server"&gt;&lt;/asp:TextBox&gt;<br />
&lt;asp:TextBox ID="Password" runat="server" TextMode="Password"&gt;&lt;/asp:TextBox&gt;<br />
&lt;asp:LinkButton ID="submitLoginBtn" CommandName="Login" runat="server"&gt;Login&lt;/asp:LinkButton&gt;<br />
&lt;asp:Literal ID="FailureText" runat="server" EnableViewState="False"&gt;&lt;/asp:Literal&gt;<br />
&lt;/LayoutTemplate&gt;<br />
&lt;/asp:Login&gt;<br />
&lt;/form&gt;<br />
</pre>
<p><strong>Update:</strong> As <a href="https://twitter.com/netaddicts/status/2875181611">Dirk</a> and <a href="https://twitter.com/JSkovgaard/status/2875573627">Jan</a> point out, this method will still produce a table surrounding the login controls. This is only a wrapper though, no table element go between the input tags, not to worry.</p>
<p>Dirk is actually working on getting the <a href="http://www.asp.net/CssAdapters/">ASP.NET 2.0 CSS Friendly Control Adapters</a> to <a href="http://our.umbraco.org/forum/developers/extending-umbraco/3137-Anyone-been-using-css-friendly-adapters-for-login-controls"> work with Umbraco</a>. Mind you, these adapters are available for <strong>.NET 2.0 only</strong>.</p>
<p>I personally set-up all my Umbraco installations with the .NET 3.5 config, so this method would not work for me. I don't view this as a big problem, I just style the wrapping table and ignore it.</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Today, I was handed a piece of HTML which featured a login form. My assignment: create this in Umbraco, using the default Membership provider.</p>
<p>This could be considered as an "Umbraco tip of the week", however this applies to ASP.NET webforms in general as well.</p>
<p>I thought about applying styles and maybe some Javascript hacking to make the login form look exactly like the design. Then, after some searching on the internet, I found out that it is actually extremely easy to apply any layout to your login form.</p>
<p>I started out with this:</p>
<pre class="brush: xml">&lt;form runat="server"&gt;<br />
&lt;asp:Login id="Login1" runat="server" /&gt;<br />
&lt;/form&gt;<br />
</pre>
<p>The designer had made some prettier input boxes with background images and the "Login" button was actually style link.</p>
<p>You can actually use something called a LayoutTemplate from<br /> within your login control.</p>
<p>The easiest way to do this is to:</p>
<ul>
<li>Open up your master page in Visual Studio</li>
<li>Go to the designer view Right-click the Login control and choose "Convert to template"</li>
<li>Start customizing the HTML</li>
</ul>
<p>However, if you want to do this manually (and who doesn't <strong>love</strong> some manual tinkering), you have to keep in mind that you need to put at least three controls in your login control:</p>
<ul>
<li>An asp:TextBox control* with an ID of: UserName</li>
<li>An asp:TextBox control* with an ID of: Password</li>
<li>Either an asp:Button an asp:ImageButton or an asp:LinkButton control with a property: CommandName="Login"</li>
</ul>
<p><em>* When I say a TextBox control, I actually mean a web control that implements ITextControl.</em></p>
<p>If you want to show an error when the login fails, add an asp:Literal with an ID of: FailureText</p>
<p>In the end, you'll end up with a piece of code that looks a bit like this (<strong>custom styling removed to keep this nice and short</strong>):</p>
<pre class="brush: xml">&lt;form runat="server"&gt;<br />
&lt;asp:Login id="Login1" runat="server"&gt;<br />
&lt;LayoutTemplate&gt;<br />
&lt;asp:TextBox ID="UserName" runat="server"&gt;&lt;/asp:TextBox&gt;<br />
&lt;asp:TextBox ID="Password" runat="server" TextMode="Password"&gt;&lt;/asp:TextBox&gt;<br />
&lt;asp:LinkButton ID="submitLoginBtn" CommandName="Login" runat="server"&gt;Login&lt;/asp:LinkButton&gt;<br />
&lt;asp:Literal ID="FailureText" runat="server" EnableViewState="False"&gt;&lt;/asp:Literal&gt;<br />
&lt;/LayoutTemplate&gt;<br />
&lt;/asp:Login&gt;<br />
&lt;/form&gt;<br />
</pre>
<p><strong>Update:</strong> As <a href="https://twitter.com/netaddicts/status/2875181611">Dirk</a> and <a href="https://twitter.com/JSkovgaard/status/2875573627">Jan</a> point out, this method will still produce a table surrounding the login controls. This is only a wrapper though, no table element go between the input tags, not to worry.</p>
<p>Dirk is actually working on getting the <a href="http://www.asp.net/CssAdapters/">ASP.NET 2.0 CSS Friendly Control Adapters</a> to <a href="http://our.umbraco.org/forum/developers/extending-umbraco/3137-Anyone-been-using-css-friendly-adapters-for-login-controls"> work with Umbraco</a>. Mind you, these adapters are available for <strong>.NET 2.0 only</strong>.</p>
<p>I personally set-up all my Umbraco installations with the .NET 3.5 config, so this method would not work for me. I don't view this as a big problem, I just style the wrapping table and ignore it.</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Umbraco tip of the week - security on your live servers</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/umbraco-tip-of-the-week-security-on-your-live-servers/</link>
                <pubDate>Mon, 13 Jul 2009 06:22:36 GMT</pubDate>
                <guid>https://cultiv.nl/blog/umbraco-tip-of-the-week-security-on-your-live-servers/</guid>
                <description>
                    <![CDATA[<p>This morning, I thought I'd protect my site a little better to get some understanding of what would be required to do so.</p>
<p>First of all, I thought I'd enable Windows authentication om my /umbraco folder. Couldn't be easier, right? Wrong.<br /> Apparently, since I am using the <a href="http://umbraco.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=23321"> .net 3.5 configuration</a> to run Umbraco in integrated pipeline mode in IIS7, some weird problem was introduced:</p>
<p><img src="https://cultiv.nl/media/584/iis7formsauth_500x133.jpg" alt="iis7formsauth" width="500" height="133" /></p>
<p>I could not disable forms authentication on the /umbraco folder. Googling for this, did not get me a lot of good results. However, I finally figured it out and it was actually a quite easy fix, the following section in the web.config needs to be disabled:</p>
<pre class="brush: xml"> &lt;authentication mode="Forms"&gt;
&lt;forms name="yourAuthCookie" loginUrl="login.aspx"
protection="All" path="/" /&gt;
&lt;/authentication&gt;
</pre>
<p>After disabling the forms authentication section, I could easily enable Windows authentication on my Umbraco folder and disable anonymous access. Great!</p>
<p>This seems to be an unintentional "bug" that I've <a href="http://umbraco.codeplex.com/WorkItem/View.aspx?WorkItemId=23469"> submitted</a> (you can vote, if you care) to the core team for future consideration.</p>
<p>After that, I thought I'd also make it impossible to show the debug information on my live site. I had actually linked to an <a href="http://umbraco.org/documentation/books/hide-debugging-features-for-production-systems"> Umbraco book</a> about this in an <a href="#" title="Umbraco tip of the week - Debugging from within the website"> earlier post</a>, so that should be easy, right? Wrong.</p>
<p>I immediately saw a glaring mistake in the rewrite code, it relied on me having ".aspx" in all of my URL's. But since I have set "useDirectoryUrls" to true (so that none of my pages end in ".aspx"), this would not work.</p>
<p>Maybe this book was written before you could even enable useDirectoryUrls, I'm not sure. I've made <a href="http://our.umbraco.org/wiki/how-tos/hide-debugging-features-for-production-systems"> a new wiki article</a> for it though.</p>
<p>The solution is as follows, any URL with a querystring in it, starting with umbDebug should be rewritten:</p>
<pre class="brush: xml">&lt;!-- Prevent the umbDebug querystrings from being used --&gt;
&lt;add name="nodebug"
virtualUrl="(.*)umbDebug.*"
rewriteUrlParameter="IncludeQueryStringForRewrite"
redirect="Application"
destinationUrl="~$1"
ignoreCase="true" /&gt;
</pre>
<p><strong>Updated:</strong> Or... as <a href="http://www.netaddicts.be/">Dirk</a> and <a href="http://twitter.com/shazwazza">Shannon</a> point out, in Umbraco 4 you can just disable the debugging by using:</p>
<pre class="brush: xml">&lt;add key="umbracoDebugMode" value="false" /&gt;
</pre>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>This morning, I thought I'd protect my site a little better to get some understanding of what would be required to do so.</p>
<p>First of all, I thought I'd enable Windows authentication om my /umbraco folder. Couldn't be easier, right? Wrong.<br /> Apparently, since I am using the <a href="http://umbraco.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=23321"> .net 3.5 configuration</a> to run Umbraco in integrated pipeline mode in IIS7, some weird problem was introduced:</p>
<p><img src="https://cultiv.nl/media/584/iis7formsauth_500x133.jpg" alt="iis7formsauth" width="500" height="133" /></p>
<p>I could not disable forms authentication on the /umbraco folder. Googling for this, did not get me a lot of good results. However, I finally figured it out and it was actually a quite easy fix, the following section in the web.config needs to be disabled:</p>
<pre class="brush: xml"> &lt;authentication mode="Forms"&gt;
&lt;forms name="yourAuthCookie" loginUrl="login.aspx"
protection="All" path="/" /&gt;
&lt;/authentication&gt;
</pre>
<p>After disabling the forms authentication section, I could easily enable Windows authentication on my Umbraco folder and disable anonymous access. Great!</p>
<p>This seems to be an unintentional "bug" that I've <a href="http://umbraco.codeplex.com/WorkItem/View.aspx?WorkItemId=23469"> submitted</a> (you can vote, if you care) to the core team for future consideration.</p>
<p>After that, I thought I'd also make it impossible to show the debug information on my live site. I had actually linked to an <a href="http://umbraco.org/documentation/books/hide-debugging-features-for-production-systems"> Umbraco book</a> about this in an <a href="#" title="Umbraco tip of the week - Debugging from within the website"> earlier post</a>, so that should be easy, right? Wrong.</p>
<p>I immediately saw a glaring mistake in the rewrite code, it relied on me having ".aspx" in all of my URL's. But since I have set "useDirectoryUrls" to true (so that none of my pages end in ".aspx"), this would not work.</p>
<p>Maybe this book was written before you could even enable useDirectoryUrls, I'm not sure. I've made <a href="http://our.umbraco.org/wiki/how-tos/hide-debugging-features-for-production-systems"> a new wiki article</a> for it though.</p>
<p>The solution is as follows, any URL with a querystring in it, starting with umbDebug should be rewritten:</p>
<pre class="brush: xml">&lt;!-- Prevent the umbDebug querystrings from being used --&gt;
&lt;add name="nodebug"
virtualUrl="(.*)umbDebug.*"
rewriteUrlParameter="IncludeQueryStringForRewrite"
redirect="Application"
destinationUrl="~$1"
ignoreCase="true" /&gt;
</pre>
<p><strong>Updated:</strong> Or... as <a href="http://www.netaddicts.be/">Dirk</a> and <a href="http://twitter.com/shazwazza">Shannon</a> point out, in Umbraco 4 you can just disable the debugging by using:</p>
<pre class="brush: xml">&lt;add key="umbracoDebugMode" value="false" /&gt;
</pre>]]>
                </content:encoded>
            </item>
            <item>
                <title>Released: Search Engine Sitemap package</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/released-search-engine-sitemap-package/</link>
                <pubDate>Wed, 08 Jul 2009 21:43:17 GMT</pubDate>
                <guid>https://cultiv.nl/blog/released-search-engine-sitemap-package/</guid>
                <description>
                    <![CDATA[<p>I've just released a simple Umbraco package that will create a sitemap XML for submitting to Google and other search engines.</p>
<p>The resulting XML is 100% compatible with the <a href="http://www.sitemaps.org/protocol.php">sitemap.org</a> specifications (which should be supported by all the major search engines).</p>
<p>Of course this generator will take into account the umbNaviHide property. Also, if there is no template attached to a content item, then the resulting output would be a blank page. So these pages are not included in the sitemap either.<br /> I ran into this problem because <a href="http://our.umbraco.org/projects/blog-4-umbraco">Tim's excellent blog package</a> that I'm using generates some date folders that should not be in the sitemap.</p>
<p>I would've liked to do everything in the XSLT, but the &lt;urlset&gt; node absolutely had to be on the second line of the resulting XML before Google would accept it. So I had to put that part in the template.</p>
<p>Have fun with it and don't forget to use the <strong>thumbs up</strong> if you like it, thanks!</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>I've just released a simple Umbraco package that will create a sitemap XML for submitting to Google and other search engines.</p>
<p>The resulting XML is 100% compatible with the <a href="http://www.sitemaps.org/protocol.php">sitemap.org</a> specifications (which should be supported by all the major search engines).</p>
<p>Of course this generator will take into account the umbNaviHide property. Also, if there is no template attached to a content item, then the resulting output would be a blank page. So these pages are not included in the sitemap either.<br /> I ran into this problem because <a href="http://our.umbraco.org/projects/blog-4-umbraco">Tim's excellent blog package</a> that I'm using generates some date folders that should not be in the sitemap.</p>
<p>I would've liked to do everything in the XSLT, but the &lt;urlset&gt; node absolutely had to be on the second line of the resulting XML before Google would accept it. So I had to put that part in the template.</p>
<p>Have fun with it and don't forget to use the <strong>thumbs up</strong> if you like it, thanks!</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Released: Contact Form Package</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/released-contact-form-package/</link>
                <pubDate>Wed, 01 Jul 2009 17:06:09 GMT</pubDate>
                <guid>https://cultiv.nl/blog/released-contact-form-package/</guid>
                <description>
                    <![CDATA[<p>While building a website last week, I was looking for a way to make a simple contact form. Unfortunately, there was nothing available on <a href="http://our.umbraco.org">our.umbraco.org</a>. So I made my own package and it is now <a href="http://our.umbraco.org/projects/cultiv-contact-form">available</a> for download. I've also added <a href="http://our.umbraco.org/projects/cultiv-contact-form/requests-and-questions/2662-How-to-relay-mail-through-Gmail"> a tip</a> to the forum to show how you can relay mail through Gmail if you don't have (or want) a mail server on your hosting machine.</p>
<p>Here's a few screenshots to show that it is highly configurable:</p>
<p><img src="https://cultiv.nl/media/558/contactform1_500x113.jpg" alt="contactform1" width="500" height="113" /></p>
<p>Of course you can just enter some content and add the bodyText field to your template to make it show up on the contact page. Here you can see I added a "Thank you" page. After the website visitor submits the form, they will be redirected here. You can configure any other page that you want.</p>
<p><img src="https://cultiv.nl/media/563/contactform2.jpg" alt="contactform2" width="422" height="399" /></p>
<p>Here again a reference to the thank you page. The form is completely empty by default so it might be a good idea to fill in the label names here.</p>
<p><img src="https://cultiv.nl/media/568/contactform3.jpg" alt="contactform3" width="407" height="307" /></p>
<p>The error messages are also empty by default, add whatever text you need here.</p>
<p><img src="https://cultiv.nl/media/573/contactform4.jpg" alt="contactform4" width="405" height="322" /></p>
<p>And finally you can set up some properties for the mail that will be sent.</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>While building a website last week, I was looking for a way to make a simple contact form. Unfortunately, there was nothing available on <a href="http://our.umbraco.org">our.umbraco.org</a>. So I made my own package and it is now <a href="http://our.umbraco.org/projects/cultiv-contact-form">available</a> for download. I've also added <a href="http://our.umbraco.org/projects/cultiv-contact-form/requests-and-questions/2662-How-to-relay-mail-through-Gmail"> a tip</a> to the forum to show how you can relay mail through Gmail if you don't have (or want) a mail server on your hosting machine.</p>
<p>Here's a few screenshots to show that it is highly configurable:</p>
<p><img src="https://cultiv.nl/media/558/contactform1_500x113.jpg" alt="contactform1" width="500" height="113" /></p>
<p>Of course you can just enter some content and add the bodyText field to your template to make it show up on the contact page. Here you can see I added a "Thank you" page. After the website visitor submits the form, they will be redirected here. You can configure any other page that you want.</p>
<p><img src="https://cultiv.nl/media/563/contactform2.jpg" alt="contactform2" width="422" height="399" /></p>
<p>Here again a reference to the thank you page. The form is completely empty by default so it might be a good idea to fill in the label names here.</p>
<p><img src="https://cultiv.nl/media/568/contactform3.jpg" alt="contactform3" width="407" height="307" /></p>
<p>The error messages are also empty by default, add whatever text you need here.</p>
<p><img src="https://cultiv.nl/media/573/contactform4.jpg" alt="contactform4" width="405" height="322" /></p>
<p>And finally you can set up some properties for the mail that will be sent.</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Umbraco tip of the week: Redirects</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/umbraco-tip-of-the-week-redirects/</link>
                <pubDate>Sun, 28 Jun 2009 16:44:25 GMT</pubDate>
                <guid>https://cultiv.nl/blog/umbraco-tip-of-the-week-redirects/</guid>
                <description>
                    <![CDATA[<p>So you start out building your website without knowing exactly what you are doing. You add new nodes under "Content" and it looks nice, but then you try adding navigation...</p>
<p>The default XSLT navigation templates only work when you add a node under "Content" and then all of your content under that. Luckily, it's easy enough to move all your content under a new item. But what should that item be?</p>
<p>I tend to start with a document type of "RedirectFolder", for example this is what my content section looks like right now:</p>
<p><img src="https://cultiv.nl/media/665/redirectfolder_500x104.jpg" alt="redirectfolder" width="500" height="104" /></p>
<p>The documentType contains two properties of the type "contentPicker" and their aliases are <strong>umbracoRedirect</strong> and <strong>umbracoInternalRedirectId</strong>. Once you pick a page, the redirecting will be done automagically by Umbraco.</p>
<p>The umbracoInternalRedirectId property kind of does what it says: it will load the selected page's content transparently; no url change. Thanks to <a href="http://blog.percipientstudios.com/2009/6/22/codegarden-%2709-presentation.aspx"> Doug Robar</a> for telling us about this hidden gem at CodeGarden '09!</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>So you start out building your website without knowing exactly what you are doing. You add new nodes under "Content" and it looks nice, but then you try adding navigation...</p>
<p>The default XSLT navigation templates only work when you add a node under "Content" and then all of your content under that. Luckily, it's easy enough to move all your content under a new item. But what should that item be?</p>
<p>I tend to start with a document type of "RedirectFolder", for example this is what my content section looks like right now:</p>
<p><img src="https://cultiv.nl/media/665/redirectfolder_500x104.jpg" alt="redirectfolder" width="500" height="104" /></p>
<p>The documentType contains two properties of the type "contentPicker" and their aliases are <strong>umbracoRedirect</strong> and <strong>umbracoInternalRedirectId</strong>. Once you pick a page, the redirecting will be done automagically by Umbraco.</p>
<p>The umbracoInternalRedirectId property kind of does what it says: it will load the selected page's content transparently; no url change. Thanks to <a href="http://blog.percipientstudios.com/2009/6/22/codegarden-%2709-presentation.aspx"> Doug Robar</a> for telling us about this hidden gem at CodeGarden '09!</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Umbraco tip of the week - Debugging from within the website</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/umbraco-tip-of-the-week-debugging-from-within-the-website/</link>
                <pubDate>Fri, 19 Jun 2009 11:24:13 GMT</pubDate>
                <guid>https://cultiv.nl/blog/umbraco-tip-of-the-week-debugging-from-within-the-website/</guid>
                <description>
                    <![CDATA[<p>Not only can you debug your umbraco site by adding "?umbDebugShowTrace=true" to the current URL, but you can also show a list of element in the page using "?umbDebug=true".</p>
<p>Using the URL rewriting feature, you can also disable the debug querystrings so that you don't disclose too much information on your live server, see the <a href="http://umbraco.org/documentation/books/hide-debugging-features-for-production-systems"> Umbraco book</a> on how to do this.</p>
<p>I was developing a custom module earlier this week and noticed that I could just add a trace.write statement to see why it did not work on the live server. Turns out that the problem was somewhere else completely, which I quickly found out once I started adding some trace statements. Nice!</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Not only can you debug your umbraco site by adding "?umbDebugShowTrace=true" to the current URL, but you can also show a list of element in the page using "?umbDebug=true".</p>
<p>Using the URL rewriting feature, you can also disable the debug querystrings so that you don't disclose too much information on your live server, see the <a href="http://umbraco.org/documentation/books/hide-debugging-features-for-production-systems"> Umbraco book</a> on how to do this.</p>
<p>I was developing a custom module earlier this week and noticed that I could just add a trace.write statement to see why it did not work on the live server. Turns out that the problem was somewhere else completely, which I quickly found out once I started adding some trace statements. Nice!</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Presenting: The CleanHome package</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/presenting-the-cleanhome-package/</link>
                <pubDate>Sun, 14 Jun 2009 19:46:38 GMT</pubDate>
                <guid>https://cultiv.nl/blog/presenting-the-cleanhome-package/</guid>
                <description>
                    <![CDATA[<p>Every time you start a new Umbraco project, there is one thing that you will do first: Set-up a home page.<br /> As this takes a few minutes, I've created a simple package that will help you out by installing the home page.</p>
<p><a href="/data/packages/CleanHome_1.0.0.zip">CleanHome</a> will give you a ContentPage document type linked to a master page that sets you up with an XHTML 1.0 strict document type.</p>
<p>The document type includes these new fields:</p>
<ul>
<li>body (richtext editor)</li>
<li>meta keywords</li>
<li>meta description</li>
<li>alternate title (to use in &lt;title&gt; tag for example)</li>
<li>alternate navigation title</li>
<li>hide in navigation checkbox (alias: umbracoNaviHide, to use with default XSLT templates)</li>
</ul>
<p>There's also a stylesheet reference and a favicon reference in the master page.</p>
<p>The stylesheet contains Eric Meyer's <a href="http://meyerweb.com/eric/thoughts/2007/04/12/reset-styles/">reset-styles</a> to start you off with the cleanest possible page.<br /> <br /> Your new "home page" <a href="http://validator.w3.org">validates</a> as XHTML strict and the CSS file is also completely <a href="http://jigsaw.w3.org/css-validator/">valid</a>.<br /> <br /> <strong>Warning:</strong> This will create a document type and Master/Childpage with the name "ContentPage", a content item named "Home" and a CSS files called styles.css. If any of these already exist in your site, you WILL get errors.<br /> <br /> This package is specifically meant for new, empty websites. You can view it as a bare-bones version of the Runway package.</p>
<p>Download CleanHome <a href="/data/packages/CleanHome_1.0.0.zip">here</a>.</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>Every time you start a new Umbraco project, there is one thing that you will do first: Set-up a home page.<br /> As this takes a few minutes, I've created a simple package that will help you out by installing the home page.</p>
<p><a href="/data/packages/CleanHome_1.0.0.zip">CleanHome</a> will give you a ContentPage document type linked to a master page that sets you up with an XHTML 1.0 strict document type.</p>
<p>The document type includes these new fields:</p>
<ul>
<li>body (richtext editor)</li>
<li>meta keywords</li>
<li>meta description</li>
<li>alternate title (to use in &lt;title&gt; tag for example)</li>
<li>alternate navigation title</li>
<li>hide in navigation checkbox (alias: umbracoNaviHide, to use with default XSLT templates)</li>
</ul>
<p>There's also a stylesheet reference and a favicon reference in the master page.</p>
<p>The stylesheet contains Eric Meyer's <a href="http://meyerweb.com/eric/thoughts/2007/04/12/reset-styles/">reset-styles</a> to start you off with the cleanest possible page.<br /> <br /> Your new "home page" <a href="http://validator.w3.org">validates</a> as XHTML strict and the CSS file is also completely <a href="http://jigsaw.w3.org/css-validator/">valid</a>.<br /> <br /> <strong>Warning:</strong> This will create a document type and Master/Childpage with the name "ContentPage", a content item named "Home" and a CSS files called styles.css. If any of these already exist in your site, you WILL get errors.<br /> <br /> This package is specifically meant for new, empty websites. You can view it as a bare-bones version of the Runway package.</p>
<p>Download CleanHome <a href="/data/packages/CleanHome_1.0.0.zip">here</a>.</p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Efficient JS/CSS handling in .Net</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/efficient-jscss-handling-in-net/</link>
                <pubDate>Mon, 08 Jun 2009 16:11:09 GMT</pubDate>
                <guid>https://cultiv.nl/blog/efficient-jscss-handling-in-net/</guid>
                <description>
                    <![CDATA[<p>This seems like a very useful project, I'll definately be looking at it for future projects. Quote:</p>
<p style="padding-left: 30px;"><em>"all of your style sheet and JavaScript files in your ASP.NET web application can be automatically minified, compressed, combined, and cached".</em></p>
<p><a href="http://www.codeproject.com/KB/aspnet/CssAndJavaScriptOptimizer.aspx"> http://www.codeproject.com/KB/aspnet/CssAndJavaScriptOptimizer.aspx</a></p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>This seems like a very useful project, I'll definately be looking at it for future projects. Quote:</p>
<p style="padding-left: 30px;"><em>"all of your style sheet and JavaScript files in your ASP.NET web application can be automatically minified, compressed, combined, and cached".</em></p>
<p><a href="http://www.codeproject.com/KB/aspnet/CssAndJavaScriptOptimizer.aspx"> http://www.codeproject.com/KB/aspnet/CssAndJavaScriptOptimizer.aspx</a></p>]]>
                </content:encoded>
            </item>
            <item>
                <title>Easily debug your custom Umbraco user controls in Visual Studio</title>
                <author>info.nospamplease@cultiv.nl (admin)</author>
                <link>https://cultiv.nl/blog/easily-debug-your-custom-umbraco-user-controls-in-visual-studio/</link>
                <pubDate>Mon, 01 Jun 2009 21:06:46 GMT</pubDate>
                <guid>https://cultiv.nl/blog/easily-debug-your-custom-umbraco-user-controls-in-visual-studio/</guid>
                <description>
                    <![CDATA[<p>I've been looking for the best way to debug when creating user controls for Umbraco, and there were no complete instructions available online.</p>
<p>The simplest way for me has been as follows.</p>
<p>When I create a new Umbraco website, I make a structure in my development folder of three folders under the site's name:</p>
<p>Database<br /> UmbracoFramework<br /> UmbracoModules</p>
<p>Logically, my database mdf/ldf files go into the "Database" folder. I do this to have everything belonging to the site close together.</p>
<p>In UmbracoFramework, I place the cleanly downloaded files of Umbraco's install. I've changed the default web.config to the .Net 3.5 version, using directory URL's.</p>
<p>One important thing to note is that, for this to work in Windows 7 (and probably Vista), you need to run Visual Studio <strong>as Administrator</strong>. If you don't, the debug session won't start. If there's any work-arounds for this, I'd love to know.</p>
<p>So let's see what we'd need to do in Visual Studio.</p>
<p>After starting VS2008, we create a new (blank) solution for this project.</p>
<p><img src="https://cultiv.nl/media/507/umbvs08_01_498x355.jpg" alt="umbvs08_01" width="498" height="355" /></p>
<p>Then we add an existing website (note you can do this either before installing Umbraco locally or right after right, it doesn't matter).</p>
<p><img src="https://cultiv.nl/media/512/umbvs08_02_500x264.jpg" alt="umbvs08_02" width="500" height="264" /></p>
<p>In your build configuration manager, make sure never to build this project, there's no need.</p>
<p><img src="https://cultiv.nl/media/517/umbvs08_03_499x314.jpg" alt="umbvs08_03" width="499" height="314" /></p>
<p>Now we can start creating a user control, add a new ASP.NET Web Application project in the folder UmbracoModules. We'll call this one (surprise!) "HelloWorld".</p>
<p>So a HelloWorld folder will be created under UmbracoModules.</p>
<p><img src="https://cultiv.nl/media/522/umbvs08_05_499x320.jpg" alt="umbvs08_05" width="499" height="320" /></p>
<p>We won't need the web.config and default.aspx, so I delete them.</p>
<p>We can automatically copy the dll/pdb files and the ascx files to the UmbracoFramework folder during each build. This is done using the post-build events:</p>
<p>XCOPY "$(ProjectDir)bin\<strong>HelloWorld</strong>.*" "$(ProjectDir)..\..\UmbracoFramework\bin\" /y<br /> XCOPY "$(ProjectDir)*.ascx" "$(ProjectDir)..\..\UmbracoFramework\usercontrols\" /y</p>
<p>Note that "Helloworld.*" is the name of the dll/pdb's we want to copy. Don't use *.* here if you reference the Umbraco framework files, else they'll get copied over the existing verions each time.</p>
<p><img src="https://cultiv.nl/media/527/umbvs08_06_500x338.jpg" alt="umbvs08_06" width="500" height="338" /></p>
<p>For both the <strong>UmbracoFramework AND the new module</strong>, we'll change the default webserver into a "custom" one. This is just a link to the local domain name we created in IIS.</p>
<p><img src="https://cultiv.nl/media/532/umbvs08_07_499x575.jpg" alt="umbvs08_07" width="499" height="575" /></p>
<p><img src="https://cultiv.nl/media/537/umbvs08_07_1.png" alt="umbvs08_07_1" width="498" height="315" /></p>
<p>Once everything is saved, we're done. We can start creating a new user control and put breakpoints in them.</p>
<p><img src="https://cultiv.nl/media/542/umbvs08_08_500x339.jpg" alt="umbvs08_08" width="500" height="339" /></p>
<p>Hit F5 and see what happens.</p>
<p><img src="https://cultiv.nl/media/547/umbvs08_09_500x358.jpg" alt="umbvs08_09" width="500" height="358" /></p>
<p>Voila! A breakpoint being hit, we can start debugging.</p>]]>
                </description>
                <content:encoded>
                    <![CDATA[<p>I've been looking for the best way to debug when creating user controls for Umbraco, and there were no complete instructions available online.</p>
<p>The simplest way for me has been as follows.</p>
<p>When I create a new Umbraco website, I make a structure in my development folder of three folders under the site's name:</p>
<p>Database<br /> UmbracoFramework<br /> UmbracoModules</p>
<p>Logically, my database mdf/ldf files go into the "Database" folder. I do this to have everything belonging to the site close together.</p>
<p>In UmbracoFramework, I place the cleanly downloaded files of Umbraco's install. I've changed the default web.config to the .Net 3.5 version, using directory URL's.</p>
<p>One important thing to note is that, for this to work in Windows 7 (and probably Vista), you need to run Visual Studio <strong>as Administrator</strong>. If you don't, the debug session won't start. If there's any work-arounds for this, I'd love to know.</p>
<p>So let's see what we'd need to do in Visual Studio.</p>
<p>After starting VS2008, we create a new (blank) solution for this project.</p>
<p><img src="https://cultiv.nl/media/507/umbvs08_01_498x355.jpg" alt="umbvs08_01" width="498" height="355" /></p>
<p>Then we add an existing website (note you can do this either before installing Umbraco locally or right after right, it doesn't matter).</p>
<p><img src="https://cultiv.nl/media/512/umbvs08_02_500x264.jpg" alt="umbvs08_02" width="500" height="264" /></p>
<p>In your build configuration manager, make sure never to build this project, there's no need.</p>
<p><img src="https://cultiv.nl/media/517/umbvs08_03_499x314.jpg" alt="umbvs08_03" width="499" height="314" /></p>
<p>Now we can start creating a user control, add a new ASP.NET Web Application project in the folder UmbracoModules. We'll call this one (surprise!) "HelloWorld".</p>
<p>So a HelloWorld folder will be created under UmbracoModules.</p>
<p><img src="https://cultiv.nl/media/522/umbvs08_05_499x320.jpg" alt="umbvs08_05" width="499" height="320" /></p>
<p>We won't need the web.config and default.aspx, so I delete them.</p>
<p>We can automatically copy the dll/pdb files and the ascx files to the UmbracoFramework folder during each build. This is done using the post-build events:</p>
<p>XCOPY "$(ProjectDir)bin\<strong>HelloWorld</strong>.*" "$(ProjectDir)..\..\UmbracoFramework\bin\" /y<br /> XCOPY "$(ProjectDir)*.ascx" "$(ProjectDir)..\..\UmbracoFramework\usercontrols\" /y</p>
<p>Note that "Helloworld.*" is the name of the dll/pdb's we want to copy. Don't use *.* here if you reference the Umbraco framework files, else they'll get copied over the existing verions each time.</p>
<p><img src="https://cultiv.nl/media/527/umbvs08_06_500x338.jpg" alt="umbvs08_06" width="500" height="338" /></p>
<p>For both the <strong>UmbracoFramework AND the new module</strong>, we'll change the default webserver into a "custom" one. This is just a link to the local domain name we created in IIS.</p>
<p><img src="https://cultiv.nl/media/532/umbvs08_07_499x575.jpg" alt="umbvs08_07" width="499" height="575" /></p>
<p><img src="https://cultiv.nl/media/537/umbvs08_07_1.png" alt="umbvs08_07_1" width="498" height="315" /></p>
<p>Once everything is saved, we're done. We can start creating a new user control and put breakpoints in them.</p>
<p><img src="https://cultiv.nl/media/542/umbvs08_08_500x339.jpg" alt="umbvs08_08" width="500" height="339" /></p>
<p>Hit F5 and see what happens.</p>
<p><img src="https://cultiv.nl/media/547/umbvs08_09_500x358.jpg" alt="umbvs08_09" width="500" height="358" /></p>
<p>Voila! A breakpoint being hit, we can start debugging.</p>]]>
                </content:encoded>
            </item>
    </channel>    
</rss>