3

Wednesday, March 16, 2011 by Administrator

I'm really excited and also really nervous about today, as I officially announce the first public beta of Courier 2.

Excited because I think we have something really awesome to show you: a completely rewritten staging and deployment engine for Umbraco, which can move any piece of functionality (content, media, macros, templates, you name it) between multiple instances of umbraco. Built to run outside of umbraco, and not depending on umbraco's datalayer or HttpContext.

But I'm also nervous, because Courier 2 has been under development for a long time, and I don't want to disappoint anyone, or present something that is not done, so we could probably keep on polishing and adding stuff to make it "just right"

But today I decided that a Beta is ready, because what we have now, is alread kick-ass, it solves a ton of really hard problems in regard to moving data back and forth between installations and it does it in the safest possible way, it will make your umbraco life so much easier. No more updating directly on the live server because deployment was too hard, no more missing types, css, or files, and no more time spend on going through ever little damn change, to ensure that it works on the new instance.

So today we launch the public beta, so we can get all your valuable feedback to make this as stable and flexible as possible.

What can I do with the beta?

First all, this is a real beta not a "google beta", it will have bugs, it could even have bugs that wipe out your website or make your site unstable, so do not use this without a backup, and never ever on a live site, you been warned.

You can move any umbraco object from one location to another, either by simply right-clicking the item in the tree UI and select where you want to put it, or you can build an entire set of objects you would like to move at once, currently called a "revision"

Now the neat part is that Courier 2 automatically detects dependencies on which selected Item depends on, so if you for example select a single content page courier will do this:

  • Detect if page has a parent
  • Detect if page has a document type
  • Detect if page has a template
  • Detect if page contains macros, links and images

Courier will then do the same for all those dependencies and their dependencies, so we end up with a pretty complex tree of cross-references. When Courier installs these items on the new instance, it will then go through this web of dependencies and make sure they are all installed in the right order.

 

 

Whats missing?

Polish! and UI. There is a UI one in place now, but we are not at all done, making that as clean as we want it. So still a lot to do there.

There are still a couple of internal look-ups in the different managers that needs some refactoring, but nothing that will affect you, it's more to do with making the internals consistent and avoid any "hacks".

Under the hood...

...Is a ton of public APIs so you can actually write your own deployment client, look in the developer docs on the build server, and in the Sample console application source which is up there as well.

Documentation on how to use these things to the max are under way, and will be announced as soon as possible.

Download docs here

Report bugs

We need to get the bugs and feedback reported, this is the only way that we can improve the stability of Courier 2, so it can run in any setting and fit into any need.

You can report bugs from the Courier UI, or by going to this page.

Download beta builds

The beta is released on our build-server so it will get daily updates. Chances are that, if you file a bug report, it will be fixed the next day. Simply keep an eye on the Courier dashboard in Umbraco which lists the most recent changes (also available here)

Download courier beta here

Sunday, March 13, 2011 by Gareth Evans

Part 5 of the feature walkthrough continues with features available in umbraco 4.7.
You should be using the 4.7 RC or higher for these examples.
Today, I'm covering the changes between the 4.7 beta and RC1
Sorry this post is a little late, the RC has been out for a while now.

Fixed Bugs
We've fixed a lot of little bugs reported on codeplex and the forums.
The most notable was that you couldn't call OrderBy with a single descending column.
There's better support for your expressions in .Where too, but more on that below…

DateTime property support
The first releases of 4.7 didn't gracefully handle DateTime properties, they'd still return as string. Now, you can do the following:

@Model.Children.Where("updateDate < DateTime.Now.AddDays(-2)")

This didn't work previously in 4.7beta because updateDate was still boxed as an object and object < DateTime can't be implicitly converted. The underlying change here is that now the left hand side of your expression will be unboxed to the type of the right hand side, if it's a node. This means that because DateTime.Now.AddDays(-2) returns a date time and updateDate returns a Func<DynamicNode,object> the object gets unboxed to be a DateTime (which it was anyway)

IsProtected & HasAccess

We've added helper methods (these have changed to properties in the 4.7 final) on DynamicNode to check to see if a given node is protected or if the currently logged in (or not) user has access to that node.
Here's an example:

@foreach(var item in Model.Children)
{
    if(item.HasAccess())
    {
        @item.Name <br/>
    }
}


Warning: HasAccess and IsProtected are methods in 4.7 RC, but in the 4.7 Final, they're Properties. This means you will need to drop the () off the calls if you use this syntax.

Better Tree Navigation

The 4.7 beta release contained a method - AncestorOrSelf, which allowed you to get the most top-level node in your content tree.
In 4.7 RC, we've added some extra methods which give you more flexible support over navigating the tree.

Each of these methods have 3 overloads.
1) An empty call .Method() - returns the default condition, e.g. all nodes that match the given call
2) A level filtered call .Method(int) - returns nodes which are <= or >= (depending on if you're using Ancestors or Descendants) the desired number
3) A node type alias filtered call .Method(string) - returns nodes which have the matching node type alias (or the first in the case of AncestorOrSelf)

The AncestorOrSelf method itself has been upgraded to support the same overloads too.

.AncestorsOrSelf
Get all the ancestors (parents) walking up the tree and return them as a DynamicNodeList

@foreach(var item in Model.AncestorsOrSelf())
{
    @item <br/>
}

.Descendants
Get all the children [deep] of the current node, by collecting the children.
.Children will only return the immediate children, whereas Descendants will return all of them (children of children..)

.DescendantsOrSelf
The same as Descendants, but will not return the current node as the first item in the list

.Ancestors
The same as .AncestorsOrSelf but will not return the current node as the first item in the list

DynamicNodeWalker - Our secret weapon in the fight against the Rebel XSLT alliance

I don't know about you, but I always found navigating around nodes in XSLT to be difficult. If you had a node, and you wanted to go to the first child, or the next sibling.. well, good luck.
It's possible, but it's not easy.
In the 4.7 RC, we added DynamicNodeWalker - this is mostly just an internal [as in you never see this in your Razor files] name, but I like the walker reference (and, no, i'm not a huge SW fan)

DynamicNodeWalker gives us some more methods on a DynamicNode.
The methods are PrototypeJs inspired, a javascript library I've used extensively but has largely fallen to the JQuery empire.

These methods are: Up/Down/Next/Previous.
Each method will take no parameters, which is equivalent to one "step" or an integer which is equivalent to a number of steps.

For the following examples, I'm using a content tree which looks like this:


Company
    Division 1
        Department
            Team 1
                Employee 1
                Employee 2
            Team 2
        Department 2
            Team 3
                Employee 3
                Employee 4
            Team 4
        Department 3
        Department 4
    Division 2

Assuming you're currently sitting on Company…


Model.Down().Next() //Division 2
Model.Down(1).Next().Down(1) //Employee 3


Or, if you're on Employee 3..


Model.Up(1).Previous().Down().Next() // Team 2
Model.Next() // Employee 4

Each of these methods will only ever return a single node, so in the case of Down, it's the first child, for Next, it's the following sibling.
If a node doesn't match the requested node, you'll get null - so look out for null references. If you get "Sequence contains no elements" or "Cannot perform runtime binding on a null reference" then you should check to make sure that the steps (int parameter) and directions you're using match your tree.

.Contains (methods on properties)
In the 4.7 beta, we had pretty good support for .Where - you could check node values, but one thing that didn't work was calling methods on those values.
For example:


@foreach(var item in Model.Children.Where("bodyText.Contains(\"cat\")"))
{
    @item.Name <br/>
}


Wouldn't work.
This is now fixed in 4.7 RC.
Warning: A bug was pointed out on the forum with this which has been fixed in 4.7 Final - which is that if you're performing multiple checks, this won't work:


@foreach(var item in Model.Children.Where("bodyText.Contains(\"cat\") || !(bodyText.Contains(\"dog\"))"))
{
    @item.Name <br/>
}

.ContainsAny (and extension method support)

Taking an example case - you're using the Contains example above, and you want to check for multiple keywords.
In 4.7 Beta, you could do this:


var items = @Model.Children.Where("Name.Contains(\"cat\") || Name.Contains(\"dog\") || Name.Contains("\fish\")")


Not very nice is it? What if you had more than 3 keywords to check?
In 4.7 RC, you can do this:


var values = new Dictionary<string,object>();
var keywords = new List<string>();
keywords.Add("cat");
keywords.Add("dog");
keywords.Add("fish");
values.Add("keywords",keywords);
var items = @Model.Children.Where("Name.ContainsAny(keywords)", values); 


Certainly a lot more readable, though verbose.
The keywords List<string> can come from somewhere else though.

ContainsAny is an extension method, defined within the Razor implementation - however because of the way the method is loaded and invoked, you can write your own and drop them in the bin folder like the example in part 3

Here's the actual implementation for ContainsAny:


public static bool ContainsAny(this string haystack, List<string> needles)
{
    if (!string.IsNullOrEmpty(haystack) || needles.Count > 0)
    {
        foreach (string value in needles)
        {
            if (haystack.Contains(value))
                return true;
        }
    }
    return false;
}


MediaById and NodeById new overloads

We've added another couple of overloads to MediaById and NodeById that take List<object> and params object[]
These let you return multiple nodes as a list.
The intention for these methods is to give better support when working with the uComponents multi node tree picker.
MediaById returns a new type, DynamicMediaList

Warning: DynamicMediaList is just a list wrapper, it doesn't support OrderBy or Where like DynamicNodeList does.

Here's an example of the new overloads being used:
I have a property on my document type which uses a multi node tree picker, and it's set to CSV type.
Warning: I tested the below sample and unfortunately the decimal handling code in DynamicNode caught the CSV string and turned it into a decimal. I've fixed this for the final.


@{

var nodes = @Model.NodeById(Model.multiChildPicker);
foreach(var node in nodes)
{
    @node.Name <br/>
}

}

This will work in the RC (assuming those node ids are valid)


@{

var nodes = @Model.NodeById(1024,2048,4096);
foreach(var node in nodes)
{
    @node.Name <br/>
}

}

DynamicNull
In the beta, when a property or type wasn't found, we just returned null.
This broke handling, particularly with True/False types which didn't have a value (null instead of 0)

The 4.7 RC will return a new type, DynamicNull which you can test for.
This was added so that a .Where against a property which existed on some nodes in the set but not on others, wouldn't crash.
.Where explicitly checks for this type and returns a default value (false)
An example of this is @Model.Children.Where("umbracoNaviHide != true") and not all of the nodes in your children have that property

You can explicitly check for it like this:

@using umbraco.MacroEngines;
@if(@Model.propertyNameThatDoesntExist.GetType() == typeof(DynamicNull))
{

}

IHtmlString
Finally, in 4.7 Beta, if you define a property on your document type using the RTE editor, you have to use @Html.Raw in the beta to decode the HTML.
In 4.7 RC, we auto-detect this type and return it as IHtmlString which makes the view engine treat it as HTML.

You should only need to use @Html.Raw if you're not using the RTE editor.



Conclusion

This post ended up being way longer than I expected!
A few more changes have been made for the 4.7 final, if you're code inclined, feel free to check out the commit messages, but otherwise, stay tuned for Part 6 after the 4.7 final release

I'm Gareth Evans, Follow me at @agrath on twitter, and here's a few links:
The new Razor forum on our.umbraco: http://our.umbraco.org/forum/developers/razor
Codeplex for any feature requests or bugs: http://umbraco.codeplex.com/

Read more from the Umbraco Razor walkthrough series

Part 1
Part 2
Part 3
Part 4
Part 5
Part 6
Part 7
Part 8

Tuesday, March 08, 2011 by Niels Hartvig

On March 15th the voting for the 2011 Umbraco MVPs begin. If that sounds all gibberish to you, don't panic - I'll (try to) explain it all in this post!

What's an MVP

MVPs are quite common in different projects and they're all inspired by Microsofts "Most Valued Professional" program. In Umbraco MVP stands for "Most Valued People" as we see at least as big value in amateurs as in professionals. In fact several Umbraco MVPs started as amateurs only to find that Umbraco is now the cornerstone of their professional career.

An MVP is a person who's not a part of the core team nor a part of the Umbraco HQ (the company), but in some other way adds extraordinary value to the project. Looking back at previous MVPs this translate into being friendly in the forum or making incredible and highly useful packages. In other words, MVPs represent the best of the community which is the last building block in what makes the foundation of the Umbraco project; the company, the core team and the community.

How does one become an MVP

We nominate the candidates for the 2011 MVPs on Tuesday the 15th of 2011 based on the people who got most karma on 'Our' from March 14th 2010 to March 14th 2011. The twenty people with most karma who isn't either a part of the HQ or the core team will be selected and the community can start voting. This year, you can vote on three people (giving them 5, 3 and 1 point respectively) and you can only vote once and not change your vote. So make sure to consider your votes carefully! In order to vote you'll need to have a profile on Our Umbraco.

The voting ends on April 15th 2011 and we'll notify the winners directly. From here it gets really tough as you'll have to keep it a secret until CodeGarden '11 where we'll officially announce the MVPs. Being the magician I am, I know that you're thinking then why not just wait with ending the voting until CodeGarden, right? Well, there's a good reason which brings me to the benefits of becoming an MVP!

The benefits

The number one benefit is obviously the honor. As the nomination of MVPs are solely in the hands of the community, becoming an MVP means that you're among the five most regarded and appreciated people in a community over 10.000 people strong. It takes a lot of effort, courage and patience and the biggest benefit in my humble opinion is the loads of virtual high fives you'll get.

There is another benefit too, though. You'll get free admission to the annual developer conference, CodeGarden. In fact you'll also get free accommodation at the best business hotel in Copenhagen during the conference too. Oh, and we'll pay for your flight no matter where in the world you live. Not even Microsoft does that to their MVPs! But there's one more thing and whether it's a benefit or not, I'll leave it for you to decide!

The CodeGarden Retreat

Four years ago we started what became a tradition - the CodeGarden retreat. We invite the most active cores, the HQs and the MVPs to an extended weekend in a country house right before CodeGarden. It's four very long days and nights where we combine deep talks on the future of Umbraco with socializing. And since the beginning it has been where the best ideas for Umbraco has be coined. For four days we got twenty very different Umbracians together without customer deadlines nor any it-cannot-be-done mentality. The sky is the limit (and so is the beer tap we've learned). It's fun, but it's much easier to show videos of the 2008 and 2009 retreats (unfortunately, I didn't get a video done in 2010):

2009:

2008:

Godspeed to everyone who's among the twenty nominates next week. Umbraco wouldn't be Umbraco without you!

Tuesday, March 01, 2011 by Gareth Evans

Part 4 of the feature walkthrough continues with features available in the TAFKA 4.6.2 release.
Today, I'm covering .Where to filter nodes and .OrderBy to order nodes

RC1 is just around the corner and there's a bunch more features coming - i'll try and cover those too when they come out -
We've got more functions for navigating your tree, slightly better support for some .Where edge cases, .Where extension methods and more!

Where

Taking this implementation to the next level, we quickly found we wanted to select a random number of elements which should be visible but were still published.
An example is if you have a boolean property (defined as the True/False data type) on your document type that indicates if an item should be featured or not.

With DynamicObject (DynamicNode too, because it inherits from), the c# compiler / razor parser doesn't allow you to use the familiar lambda syntax to filter your sets.
This is because we now return a DynamicObject [DynamicNodeList] to allow method chaining.

This will not work in 4.6.1 or 4.7.

@Model.Children.Where(item => item.shouldBeFeatured);

//Lambda's cannot be used against Dynamic Objects


With the new 4.7 syntax, you can now use .Where to filter your nodesets.
To do this, we took the string parser from the 2008 linq samples and then added support for working with DynamicObjects

I saved the best for last!

A simplistic filter by a single boolean:

@Model.Children.Where("shouldBeFeatured")


A longhand filter, demonstrating the equality operator and type safety:

@Model.Children.Where("shouldBeFeatured == true")


Using NotEquals:

@Model.Children.Where("shouldBeFeatured != true")


Using GreaterThan against a numeric property

@Model.Children.Where("catCount > 1")


Using Modulus (to get the remainder of a number)
(will return any children where the number of cats is even)

@Model.Children.Where("catCount % 2 == 0") 


Using string comparisons and boolean logic (|| [or], && [and]) - also shows how to nest strings

@Model.Children.Where("menuType == \"Top Menu\ || menuType == \"Bottom Menu\"") 


Chaining into your own extension method
(will return 8 randomly selected nodes which are marked as featured items)

@Model.Children.Where("shouldBeFeatured").Random(8)


Passing Variables from outer scope into the .Where expression:
If you need to access a variable from outside the scope (e.g. a number etc) and don't want to pass it as a constant,

var maxLevelForSitemap = 4;
var values = new Dictionary<string,object>();
values.Add("maxLevelForSitemap", maxLevelForSitemap) ;        
var items = node.Children.Where("ShouldBeVisible == true && Level <= maxLevelForSitemap", values);


OrderBy

We have also added support for OrderBy, this lets you sort your nodesets by the properties on the nodes themselves.

Simplistic ordering by a single property:

@Model.Children.OrderBy("catCount")


More complex ordering by multiple properties, with descending/ascending support:

@Model.Children.OrderBy("catCount, colour desc")


Warning: There's a small bug in the 4.7 beta which means you can't order by a single descending column. This is fixed in RC1.

 

Conclusion

That pretty much wraps up my additions to Razor in 4.7beta, hopefully the new syntax improves your ability to work with razor to build websites with umbraco :)
Some more parts to come once the RC is released

I'm Gareth Evans, Follow me at @agrath on twitter, and here's a few links:
The new Razor forum on our.umbraco: http://our.umbraco.org/forum/developers/razor
Codeplex for any feature requests or bugs: http://umbraco.codeplex.com/

Read more from the Umbraco Razor walkthrough series

Part 1
Part 2
Part 3
Part 4
Part 5
Part 6
Part 7
Part 8