It's been a month since we released Mr N Picker on the world, so what better time to sum up our collective experiences of publishing our first Umbraco 7 package, and our experience of demonstrating it at the local Umbraco user group.

When you've written some code that you think would be useful to others, and you want to give back to the open-source world that has given so much to you, it's very important to have a set process for getting that bit of code across the finish line.

Out of the Mayfly team only a handful of us had actually released open-source tools or packages. Those of us that had knew that you can't just dump some code on GitHub and call it a package. For all the good intent in the world, a package is only as good as its support structure. You want people to:

  • Be able to use your code in a multitude of different ways
  • Use your package to fix problems
  • Contribute to your project
  • Be able to easily, and clearly see how to use your code

This blog post details the technical side of building a non-trivial Umbraco package, and the process of releasing, promoting, and supporting that package.

As a technical challenge, Mr N Picker took our Umbraco knowledge to the limit. Everyone involved on the project knew Umbraco well, but there is a key difference in knowing how to build a site around Umbraco, and how to extend Umbraco. Our first challenge was learning how the Multi Node Tree Picker (MNTP) worked. Thankfully, the Umbraco source code is neatly laid out, so we were able to follow the path Umbraco follows to take a root id and render a content tree. Once we knew exactly what code we were dealing with, we had to isolate and test the relevant methods to see how we would extend a MNTP to accept more than one id.

Once we knew what fields we required of our new data type, we were able to begin with the initial setup. The basic ingredients for any Umbraco package are:

  • A MANIFEST file
  • Views
  • AngularJS
  • .NET Controllers (optional)

Building a MANIFEST file was easy enough. We knew what fields we required, and how we wanted them laid out. The only issue is in how we aimed to pick up our multiple route id's within Umbraco and have them rendered in a suitable format. To do so, we created a prevalue view to handle this. Once this was hooked up alongside a set of other prevalue properties, we were ready to tackle the main problem.

We knew what content we were expecting from Umbraco, so we isolated some test input and got to work on the JavaScript side of the package. We created a single Angular controller, and modelled as much of it as possible on the existing MNTP code as we possibly could. Once we isolated the scope values we required we created a set of anonymous methods and started filling in the blanks. For many of us, this was our first time playing with AngularJS to create something bespoke, but luckily our vanilla JS knowledge coupled with the Umbraco Belle documentation was more than enough for us to navigate our way through.

We were happy with our progress, but very quickly hit a road-block. We needed to send Umbraco multiple id's, but this wasn't supported out of the box. Ultimately, we would have to create a custom tree controller in C# to hijack the input and build the content tree to our liking. Our initial testing phase showed that we could pass in the values we required using a customTreeParams property to the MNTP dialogOptions object. We aimed to modify the query string to pass in our id's and build a content tree of our own to pass to Mr N Picker.

We were able to render a content tree, and we were able to select multiple root nodes, but the bit in the middle was missing. In order to do this, we created a brand new C# class that inherits from ContentTreeController, and armed with the Umbraco source code, we got to work in overriding the PerformGetTreeNodes() method.

At this point, many of us were nervous about getting the package finished in the allotted time, but moving to C# put many of us in our element, and we quickly managed to parse the query string and get the custom content tree rendered. Once we plugged this into our Angular controller, we had a rendering tree from multiple root nodes! We even found the time to start implementing some additional features. We made quick work of implementing multiple XPath roots, and were even able to create the option to merge tree nodes if a given route was a child of another rendered tree. We had a working package with a day remaining!

As mentioned above, working code is a small part of releasing an open-source package. Not only were we missing any kind of documentation, we hadn't even started thinking about how we'd actually release the package and promote it!

Thankfully, we had a full day left for two developers and a tester to get the package across the finish line. One developer worked alongside our tester to fix any potential bugs, and to give the package a thorough test on a set of our existing code projects. The other started writing some documentation. One README.md and a fully tested package later, we were happy that our master branch was ready for release!

However, what exactly does "released" mean? We're used to consuming our code in many different ways, and as of that moment we had no public facing account on any of these platforms! We outlined the three main ways to get our code out there; Our Umbraco, GitHub, and NuGet.

First of all, we needed to get the code out there. We created a clean repository from the existing master branch, and pushed that up to GitHub. The easy part was done.

Next up, NuGet! This one worried us more than the rest, as very few of us had ever had to create a custom NuGet package for public consumption. Thankfully, there are dozens of tutorials out there for this, and with some clever scripting, this was up on NuGet.org in less than an hour. It turns out that we didn't need to be so worried after all!

Finally, Our Umbraco! Everyone on the team knew how to create packages in Umbraco, so this took hardly any time for us to do. We dusted off the Mayfly account and set up a brand new package. For consistency, we updated the README across all three platforms, and added a bunch of links to our release on each platform. After some additional QA of each package to be sure that we released working code to the public (and a few quick bug fixes) Mr N Picker was available to the world!

Well, not quite. Aside from our die-hard fans, who else would know about this package? We needed a platform to announce our hard work, and what better place to do this than the Umbraco user group in Bristol. After floating the idea around the office, Callum and Mike put themselves forward to give a presentation. After some initial prep (and a beer or two), both took to the stage and delivered a great presentation on the package itself, and our experiences in building a package at Mayfly. A few tweets later, a pull request, a raised issue, and a few hundred downloads (at this time of writing), Mr N Picker has picked up praise from around the globe.

Being involved in a project like this is invaluable for a developer. Alongside the knowledge that you helped to build a package that is being used by hundreds of developers, the knowledge we've gained by building this package has been used in other places. No longer daunted by creating custom data types, a number of our developers have been extending the Umbraco backoffice with their own bespoke data types to help the client experience. Only a handful of developers can say the same. Not only did we build a solid package, we released it. Opening the NuGet Package Manager and seeing your package in the same list as Umbraco, JSON.NET, EntityFramework, Moq, and other packages is a great feeling. Finally, we learned that a daunting problem can have an elegant solution.

Here's to Mr N Picker, and our next package under Project Yoxo!