EmbeddedMedia.config , supporting additional third party services in the Umbraco RTE 0

The RTE in Umbraco 7 (and since v4.9) offers a super simple way of inserting rich content from third party services (videos from youtube, image from flickr, …) but sometimes your editors will try to insert something that isn’t supported…


Luckily you can easily plug in additional third party services

If service support oembed

In that case it should just be a matter of adding an additinal entry to the EmbeddedMedia.config file. Let’s say you want to support videos from TED.

The details we get from oembed:

So with those details I can add a new entry to the config file (just look at the existing ones to get an overview of the xml elements you need).

1 <!– TED Settings –> 2 <provider name="TED" type="Umbraco.Web.Media.EmbedProviders.OEmbedVideo, umbraco" supportsDimensions="False"> 3 <urlShemeRegex><![CDATA[ted\.com/]]></urlShemeRegex> 4 <apiEndpoint><![CDATA[]]></apiEndpoint> 5 <requestParams type="Umbraco.Web.Media.EmbedProviders.Settings.Dictionary, umbraco"></requestParams> 6 </provider>

And now content editors can easily insert talks from


If service doesn’t support oembed

Even if the third party service doesn’t offer oembed support it’s still possible to provide this easy way of inserting rich content.

Since you can write custom providers, so if the service has an API you can take advantage of that.

Here is an example of a custom provider, this one adds Giphy support.

1 public class Giphy : AbstractProvider 2 { 3 public override bool SupportsDimensions 4 { 5 get { return false; } 6 } 7 8 public override string GetMarkup(string url, int maxWidth, int maxHeight) 9 { 10 var u = new Uri(url); 11 //Example url 12 var id = u.Segments.Last().Split(-).Last(); 13 //using public api key atm 14 var api = string.Format("{0}?api_key=dc6zaTOxFJmzC", id); 15 16 using(var apiClient = new HttpClient()) 17 { 18 19 var dataFromAPI = apiClient.GetAsync(api).Result; 20 21 if (dataFromAPI.IsSuccessStatusCode) 22 { 23 var APIresult = dataFromAPI.Content.ReadAsStringAsync(); 24 25 var result = JObject.Parse(APIresult.Result); 26 27 var embedUrl = result.SelectToken("data.images.original.url").Value<string>(); 28 29 return string.Format("<img src=\"{0}\"/>", embedUrl); 30 } 31 } 32 //fall back to a default ‘fail’ gif 33 return string.Format("<iframe src=\"//{0}\" width=\"{1}\" height=\"{2}\" frameBorder=\"0\" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>", 34 "bJAi9R0WWOohO",250,153); 35 } 36 }

So once this provider is in place we also need to add an entry to the config file

1 <!– Giphy Settings , not an OEmbed one –> 2 <provider name="Giphy" type="AnimatedGifs.Giphy, AnimatedGifs"> 3 <urlShemeRegex><![CDATA[giphy\.com/]]></urlShemeRegex> 4 </provider>

And now our content editors can insert gifs Glimlach


So that’s how you can use the EmbeddedMedia.config file, sourcecode for the example provider is available on github

Making use of resources and services on your Umbraco v7 Controllers 1

As you can see on the Umbraco v7 API documentation, v7 is shipped with several resources and services you can use in your own controllers. Lets take a look at a simple example. The notification service.

I’m actually making use of the service in the demo project, to display a success notification if the custom item has been saved correctly.


First simply inject the service (as a param on your controller function, similiar to how $scope is injected)

1 angular.module("umbraco").controller("People.PersonEditController", 2 function ($scope, personResource, notificationsService) { 3

And after that you can make use of the service

1 notificationsService.success("Success", person.firstName + " " + person.lastName + " has been saved");

That’s it! Make sure to check out the docs to see the options you have with each service/resource.

Custom sections/trees/Pages/Dialogs in Umbraco v7 7

As promised as a follow up on the example project i posted I’ll also outline the different steps.

Step 1: Petapoco

The custom tree needs some data to work with and to do that we’ll use the db and since Umbraco is shipped with Petapoco we can take advantage of that. So first I’ll define the POCO:

1 [TableName("People")] 2 public class Person 3 { 4 public Person(){} 5 6 [PrimaryKeyColumn(AutoIncrement = true)] 7 public int Id { get; set; } 8 public string FirstName { get; set; } 9 public string LastName { get; set; } 10 11 public override string ToString() 12 { 13 return FirstName + " " + LastName; 14 } 15 }

Then make sure this table is created if it doesn’t exist

1 public class RegisterEvents : ApplicationEventHandler 2 { 3 protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) 4 { 5 var db = applicationContext.DatabaseContext.Database; 6 7 //Check if the DB table does NOT exist 8 if (!db.TableExist("People")) 9 { 10 //Create DB table - and set overwrite to false 11 db.CreateTable<Person>(false); 12 } 13 } 14 }


Step 2: The Api Controller

Next we’ll create the controller that will contain the different methods for crud operations with our data (again using Petapoco)

1 [PluginController("Example")] 2 public class PersonApiController : UmbracoAuthorizedJsonController 3 { 4 public IEnumerable<Person> GetAll() 5 { 6 7 var query = new Sql().Select("*").From("people"); 8 return DatabaseContext.Database.Fetch<Person>(query); 9 } 10 11 public Person GetById(int id) 12 { 13 14 var query = new Sql().Select("*").From("people").Where<Person>(x => x.Id == id); 15 return DatabaseContext.Database.Fetch<Person>(query).FirstOrDefault(); 16 17 } 18 19 public Person PostSave(Person person) 20 { 21 if (person.Id > 0) 22 DatabaseContext.Database.Update(person); 23 else 24 DatabaseContext.Database.Save(person); 25 26 return person; 27 } 28 29 public int DeleteById(int id) 30 { 31 return DatabaseContext.Database.Delete<Person>(id); 32 } 33 34 }


Step 3: The section

We’ll place our new tree in a new section so let’s create a new section

1 [Application("example", "Example","icon-people", 15)] 2 public class Section: IApplication {}


Basicly you need a class and decorate that with the Application attribute, that needs an application alias, name, icon and sort order.

Make sure to give your user access to this section otherwise it won’t show up yet.

Step 4: The tree

Next we’ll create the tree that will list data from our custom People table

1 [Tree("example", "peopleTree", "People")] 2 [PluginController("Example")] 3 public class PeopleTreeController: TreeController 4 { 5 6 7 protected override Umbraco.Web.Models.Trees.TreeNodeCollection GetTreeNodes(string id, System.Net.Http.Formatting.FormDataCollection queryStrings) 8 { 9 //check if we’re rendering the root node’s children 10 if (id == Constants.System.Root.ToInvariantString()) 11 { 12 var ctrl = new PersonApiController(); 13 var nodes = new TreeNodeCollection(); 14 15 foreach (var person in ctrl.GetAll()) 16 { 17 var node = CreateTreeNode( 18 person.Id.ToString(), 19 "-1", 20 queryStrings, 21 person.ToString(), 22 "icon-user", 23 false); 24 25 nodes.Add(node); 26 27 } 28 return nodes; 29 } 30 31 //this tree doesn’t suport rendering more than 1 level 32 throw new NotSupportedException(); 33 } 34 35 protected override Umbraco.Web.Models.Trees.MenuItemCollection GetMenuForNode(string id, System.Net.Http.Formatting.FormDataCollection queryStrings) 36 { 37 //not worying about menu atm 38 var menu = new MenuItemCollection(); 39 return menu; 40 } 41 }

So we return a TreeNodeCollection and create a TreeNode for each item in our data source (People table). So when we deploy this we should have a tree listing the data in the table now.

The menu is emtpy atm but we’ll get to that later on.

Step 5: AngularJS resource

Before we start with the edit page and the dialogs we’ll create an AngularJS resource that interacts with the APIController and that we will be able to inject in our future AngularJS controllers

1 angular.module("umbraco.resources") 2 .factory("personResource", function ($http) { 3 return { 4 getById: function (id) { 5 return $http.get("backoffice/Example/PersonApi/GetById?id=" + id); 6 }, 7 save: function (person) { 8 return $"backoffice/Example/PersonApi/PostSave", angular.toJson(person)); 9 }, 10 deleteById: function(id) { 11 return $http.delete("backoffice/Example/PersonApi/DeleteById?id=" + id); 12 } 13 }; 14 });

Step 6: Package manifest

And of course make sure Umbraco knows about this new file by adding a package manifest

1 { 2 javascript: [ 3 ~/App_Plugins/Example/person.resource.js 4 ] 5 }

Step 7: The edit page controller

The AngularJS controller used by the edit page, will fetch a person by it’s id using the resource and will also save a person

1 angular.module("umbraco").controller("People.PersonEditController", 2 function ($scope, $routeParams, personResource, notificationsService) { 3 4 $scope.loaded = false; 5 6 if ($ == -1) { 7 $scope.person = {}; 8 $scope.loaded = true; 9 } 10 else{ 11 //get a person id -> service 12 personResource.getById($ (response) { 13 $scope.person =; 14 $scope.loaded = true; 15 }); 16 } 17 18 $ = function (person) { 19 (response) { 20 $scope.person =; 21 22 notificationsService.success("Success", person.firstName + " " + person.lastName + " has been saved"); 23 }); 24 }; 25 });

of course also make sure to update your manifest file to include this js file

Step 8: the edit page view

The actual edit page, will show an input for the firstName and lastName

1 <form name="personForm" 2 ng-controller="People.PersonEditController" 3 ng-show="loaded" 4 ng-submit="save(person)" 5 val-form-manager> 6 <umb-panel> 7 <umb-header> 8 9 <div class="span7"> 10 <umb-content-name placeholder="@placeholders_entername" 11 ng-model="person.firstName" /> 12 </div> 13 14 <div class="span5"> 15 <div class="btn-toolbar pull-right umb-btn-toolbar"> 16 <umb-options-menu ng-show="currentNode" 17 current-node="currentNode" 18 current-section="{{currentSection}}"> 19 </umb-options-menu> 20 </div> 21 </div> 22 </umb-header> 23 24 <div class="umb-panel-body umb-scrollable row-fluid"> 25 <div class="tab-content form-horizontal" style="padding-bottom: 90px"> 26 <div class="umb-pane"> 27 28 29 30 <umb-control-group label="First name" description="Person’s first name’"> 31 <input type="text" class="umb-editor umb-textstring" ng-model="person.firstName" required /> 32 </umb-control-group> 33 34 <umb-control-group label="Last name" description="Person’s last name’"> 35 <input type="text" class="umb-editor umb-textstring" ng-model="person.lastName" required /> 36 </umb-control-group> 37 38 39 <div class="umb-tab-buttons" detect-fold> 40 <div class="btn-group"> 41 <button type="submit" data-hotkey="ctrl+s" class="btn btn-success"> 42 <localize key="buttons_save">Save</localize> 43 </button> 44 </div> 45 </div> 46 47 </div> 48 </div> 49 </div> 50 51 </umb-panel> 52 </form>


Step 9: Update the treecontroller with menu items

So we also want some actions on our tree, a refresh and create on the root and a delete on the items

1 protected override Umbraco.Web.Models.Trees.MenuItemCollection GetMenuForNode(string id, System.Net.Http.Formatting.FormDataCollection queryStrings) 2 { 3 var menu = new MenuItemCollection(); 4 5 if (id == Constants.System.Root.ToInvariantString()) 6 { 7 // root actions 8 menu.Items.Add<CreateChildEntity, ActionNew>(ui.Text("actions", ActionNew.Instance.Alias)); 9 menu.Items.Add<RefreshNode, ActionRefresh>(ui.Text("actions", ActionRefresh.Instance.Alias), true); 10 return menu; 11 } 12 else 13 { 14 15 menu.Items.Add< ActionDelete>(ui.Text("actions", ActionDelete.Instance.Alias)); 16 17 } 18 return menu; 19 }


Step 10: The delete controller

For create we don’t need a controller and view since it uses a convention but for the delete one we do.

1 angular.module("umbraco") 2 .controller("People.PersonDeleteController", 3 function ($scope, personResource, navigationService) { 4 $scope.delete = function (id) { 5 personResource.deleteById(id).then(function () { 6 navigationService.hideNavigation(); 7 8 }); 9 10 }; 11 $scope.cancelDelete = function () { 12 navigationService.hideNavigation(); 13 }; 14 });


Step 11: The delete view

1 <div class="umb-pane" ng-controller="People.PersonDeleteController"> 2 <p> 3 Are you sure you want to delete {{}} ? 4 </p> 5 6 <div> 7 <div class="umb-pane btn-toolbar umb-btn-toolbar"> 8 <div class="control-group umb-control-group"> 9 <a href="" class="btn btn-link" ng-click="cancelDelete()"><localize key="general_cancel">Cancel</localize></a> 10 <a href="" class="btn btn-primary" ng-click="delete("><localize key="general_ok">OK</localize></a> 11 </div> 12 </div> 13 </div> 14 </div>


And those are all the different steps invoved in creating your own section/tree/page/dialog in Umbraco v7. The complete project is available on github.

Umbraco v7 trees, DefaultMenuAlias 0

Something you can do in trees created with a TreeController is define a default menu item. So instead of having the ability to choose an action it will default to the set action (like in content it will default to create).

To do this all you have to set is the DefaultMenuAlias property on your menu.

So in the example project I created I just add menu.DefaultMenuAlias = ActionDelete.Instance.Alias;

to make delete the default action on my tree items (it’s also the only option so it makes sense to default to it).

So now I don’t get the following screen anymore (the overview of available actions)


but it will default to the delete action immedialty showing the delete dialog


If you stil wish to show the overview you can use nav.hideDialog(true) in your view

Extending the Umbraco backend Using Angularjs and WebAPI 2

After the example project I creating using MVC I thought it would be fun to show how you can now extend the Umbraco v7 backoffice with AngularJS and WepAPI. So in Umbraco v7 you have three options webforms, mvc or angularjs/webapi.

So I’ve just published a new project to github that does extactly that


I’l follow up this post with some more detailed ones describing the different steps

Umbraco Contour Masterclass 1

Better late then never! During the annual Umbraco conference codegarden I taught a workshop on Contour.

It contained the following things;

  • Modifying form markup (bootstrap markup)
  • Creating custom form elements (field types) 
  • Attaching extra functionality to a form (workflow types)
  • Connecting Contour to third party services (podio)
  • Hooking in custom validation rules
  • And making all these components as flexible as possible so you can deploy them across projects

So I just wanted to share the workbook and start solution for those that are interested in learning more about Contour.

Contour, adding custom validation without using code first 11

Just a quick post to share the answer to a question I got on the forum.

So as you can see in the code first examples, creating Contour forms code first also allows for an easy way to add extra (custom validation)

But there is also a way to add custom rules when you are designing the form in the UI.

There is an event you can hook into to add validation errors, a typical case for this would be a password and repeast password field where you need to make sure the input is the same.


So in the form designer these are just 2 password fields with no link


And to add the extra validation rules

    public class ContourValidation : ApplicationEventHandler
        protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
            FormRenderController.FormValidate += FormRenderController_FormValidate;
        void FormRenderController_FormValidate(object sender, Umbraco.Forms.Mvc.FormViewEventArgs e)
            if (e.Form.Name == "FormWithExtraValidation")
                var s = sender as Controller;
                if (s != null)
                    var pwf = e.Form.AllFields.SingleOrDefault(f => f.Caption == "Password").Id.ToString();
                    var rpwf = e.Form.AllFields.SingleOrDefault(f => f.Caption == "Repeat password").Id.ToString();
                    var password = e.Context.Request[pwf];
                    var repeatpassword = e.Context.Request[rpwf];
                    if(password != repeatpassword)
                        s.ModelState.AddModelError(rpwf, "passwords don’t match");

So hook into the FormValidate event of the FormRenderController that will fire when a form validates

You can then add extra model errors to the modelstate

Have you secured your Umbraco BE festival ticket yet? 2

Join Me, colleagues from the HQ and a whole bunch of other Umbraco devs in Antwerp on April 25th for the second Umbraco BE festival!

It’s the perfect opportunity to learn all about Umbraco v7. At this point 10 out of 12 session have been confirmed . Speakers from across Europe will share Umbraco tips and tricks. Responsive imaging, newsletters, extending the Umbraco v7 backoffice, e-commerce, automation, AngularJS and of course Mr Umbraco himself taking care of the keynote.

So check out the festival site and don’t wait to long to secure your ticket!

Integrate Umbraco Contour with third party service, post to Podio App 1

Just a quick blog post with an example on how to attach a third party service to Contour (the Umbraco form builder).

You can attach extra functionality to a Contour form by setting up workflows,

So by default a Contour form will store it’s data but if you want extra stuff (like sending an email) you can do that by adding a workflow..

There are several out of the box workflows you can use…now in my case I wanted to extend Contour to post it’s record date to a podio app

So first of all I need a podio API key, you can get that here

Once that is settled we can use the API, there is even a .net library available

Next of course is to setup an app in podio, that’s pretty easy with the app builder,

So I just created a new app that has a single item and that item has a single text block (that’s the text block we’ll populate with contour record data)


Now I’m all set the create the workflow, here is the code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml;
using System.Xml.XPath;
using Podio.API;
using Podio.API.Model;
using Podio.API.Utils.ItemFields;
using Umbraco.Forms.Core;
using Umbraco.Forms.Core.Enums;
using Umbraco.Forms.Data;
using Umbraco.Forms.Data.Storage;
namespace Contour.Addons.Podio
    public class AddRecordToPodioSpace : WorkflowType
        [Umbraco.Forms.Core.Attributes.Setting("Client id")]
        public string ClientId { get; set; }
        [Umbraco.Forms.Core.Attributes.Setting("Client secret ")]
        public string ClientSecret { get; set; }
        public string UserName { get; set; }
        public string Password { get; set; }
        public string AppId  { get; set; }
        public string PodioTextFieldId { get; set; }
        public AddRecordToPodioSpace()
            this.Id = new Guid("55517EB2-8D61-483C-A3DA-7850FCE05996");
            this.Name = "Send record to podio space";
            this.Description = "Send record to podio space";
        public override List<Exception> ValidateSettings()
            List<Exception> l = new List<Exception>();
            if (string.IsNullOrEmpty(ClientId))
                l.Add(new Exception("’ClientId’ setting has not been set"));
            if (string.IsNullOrEmpty(ClientSecret))
                l.Add(new Exception("’ClientSecret’ setting has not been set’"));
            if (string.IsNullOrEmpty(UserName))
                l.Add(new Exception("’UserName’ setting has not been set’"));
            if (string.IsNullOrEmpty(Password))
                l.Add(new Exception("’Password’ setting has not been set’"));
            return l;
        public override WorkflowExecutionStatus Execute(Record record, RecordEventArgs e)
                RecordsViewer viewer = new RecordsViewer();
                XmlNode xml = viewer.GetSingleXmlRecord(record, new System.Xml.XmlDocument());
                XPathNavigator navigator = xml.CreateNavigator();
                XPathExpression selectExpression = navigator.Compile("//fields/child::*");
                selectExpression.AddSort("@pageindex", XmlSortOrder.Ascending, XmlCaseOrder.None, "", XmlDataType.Number);
                selectExpression.AddSort("@fieldsetindex", XmlSortOrder.Ascending, XmlCaseOrder.None, "",
                selectExpression.AddSort("@sortorder", XmlSortOrder.Ascending, XmlCaseOrder.None, "", XmlDataType.Number);
                XPathNodeIterator nodeIterator = navigator.Select(selectExpression);
                string list = "<dl>";
                while (nodeIterator.MoveNext())
                    list += "<dt><strong>" +
                                nodeIterator.Current.SelectSingleNode("caption").Value) + ": </strong><dt><dd>";
                    XPathNodeIterator values = nodeIterator.Current.Select(".//value");
                    while (values.MoveNext())
                        list +=
                                .Replace("\n", "<br/>") + "<br/>";
                    list += "</dd>";
                list += "</dl>";
                Client client = Client.ConnectAsUser(ClientId,
                Item i = new Item();
                var textField = i.Field<TextItemField>(PodioTextFieldId);
                textField.ExternalId = PodioTextFieldId; 
                textField.Value = list;
                client.ItemService.AddNewItem(Convert.ToInt32(AppId), i);
            catch (Exception ex)
                return WorkflowExecutionStatus.Failed;
            return WorkflowExecutionStatus.Completed;

So all the settings I need for podio are public properties marked with the settings attribute (so I can set those up when inserting the workflow)

THen the actuall workflow code will loop through all the record data and create html list. So you see it doesn’t matter how many fields you have it will pass all of them, this code is actually borrowed from the default send email workflow code, you can get all default providers code here (sourcecode tab at the bottom)

THen it wil make use of the podio api to create a new item and add it …

When I know deploy this to the site, I see a new workflow type


When choosing that type I can setup the settings


So when the settings are valid and the workflow is attached the form will now post to podio when it’s submitted (if workflow is attached to submitted stage)


So now I have a reusable component that I can deploy whenever I need a form that needs to integrate with podio!

Advanced property editor for Umbraco v7, single file deployment 3

One of the community packages that is in progress of being migrated to v7 is uComponents, as you may know the current v4/v6 version is compiled into a single assembly so it’s easy to deploy and to update (since it’s just a single file).

As a test I wanted to see if that’s also possible with v7 prop editors (so embed the views and controllers in the assembly).

If you have seen some of the v7 prop editor examples out there you know that to define your extra components you’ll need to create a manifest file (no more need for vs)

You can also define your prop editors in code (all the core ones are defined like that) just take a look at 

So if I take the char limit example the manifest file becomes

 [PropertyEditor("Example", "Example Editor", "/App_Plugins/Example/Resource/editor.html", ValueType = "TEXT")]
    [PropertyEditorAsset(ClientDependencyType.Javascript, "/App_Plugins/Example/Resource/controller.js")]
    public class ExamplePropEditor : PropertyEditor
        protected override PreValueEditor CreatePreValueEditor()
            return new ExamplePreValueEditor();
        internal class ExamplePreValueEditor : PreValueEditor
            public ExamplePreValueEditor()
                //create the fields
                Fields.Add(new PreValueField()
                    Description = "Enter the number of chars to limit on",
                    Key = "limit",
                    View = "requiredfield",
                    Name = "Number of chars"


THe editor and controller is still the same but in vs make sure to set the build action of the js and html file to embedded resource


Final bit is getting the controller and view out of the assembly and this is done with a simple controller

   public class EmbeddedController : Controller
        public FileStreamResult Resource(string id)
            var resourceName = Assembly.GetExecutingAssembly().GetManifestResourceNames().ToList().FirstOrDefault(f => f.EndsWith(id));
            var a = typeof(EmbeddedController).Assembly;
            return new FileStreamResult(a.GetManifestResourceStream(resourceName), GetMIMEType(id));
        private string GetMIMEType(string fileId)
            if (fileId.EndsWith(".js"))
                return "text/javascript";
            if (fileId.EndsWith(".html"))
                return "text/html";
            if (fileId.EndsWith(".css"))
                return "text/stylesheet";
            return "text";

Of course since it’s a normal mvc controller it isn’t auto routed and I need to setup the routing

    public class RouteConfig
        public static void RegisterRoutes(RouteCollection routes)
                name: "Example",
                url: "App_Plugins/Example/{action}/{id}",
                defaults: new { controller = "Embedded", action = "Resource", id = UrlParameter.Optional }


And make sure that the route get’s registered when the application starts

 public class StartUpHandlers : ApplicationEventHandler
        protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)

So now we can fetch the embedded resource by requesting




And that’s it, build and just deploy the assemby to the umbraco v7 instance

Complete source of this example is available here

« Previous PageNext Page »