@Shazwazza

Shannon Deminick's blog all about web development

Powershell script to create an Umbraco package in Umbraco’s native file format

November 11, 2015 10:35

logo-powershell-umbracoSince I like using Powershell for my build scripts for various projects I thought it would be handy to create a Powershell script to create an Umbraco package in it’s native package format. I’ve added this script template to my GitHub Umbraco Scripts repository which you can see here: http://bit.ly/1kM9g9g

I’ve tried to add a bit of documentation to this script and in theory you should only need to set up the paths properly. You’ll also need to ensure that you initially create the package in the back office of Umbraco in order to generate the createdPackages.config as mentioned in the script notes.

I use this script in Articulate’s build script so at least I can also provide an example of using it which you can see here: https://github.com/Shazwazza/Articulate/blob/master/build/build.ps1

Umbraco Jupiter Plugins - Part 5 - Surface Controllers

November 29, 2011 14:31

This is the fifth blog post in a series of posts relating to building plugins for Umbraco v5 (Jupiter). This post will explain what a Surface Controller is, what they can be used for and how to create one.

Disclaimer

This post is about developing for Umbraco v5 (Jupiter) which at the time of this post is still under development. The technical details described below may change by the time Umbraco Jupiter is released. If you have feedback on the technical implementation details, please comment below.

Related Posts:

  1. Umbraco Jupiter Plugins – Part 1
  2. Umbraco Jupiter Plugins – Part 2 – Routing
  3. Umbraco Jupiter Pluings – Part 3 – Trees
  4. Umbraco Jupiter Pluings – Part 4 – Editors

What is a Surface Controller?

A Surface Controller is an MVC controller that interacts with the front-end (or render layer) of Umbraco. An example of a Surface Controller could be a controller that has a Child Action used to display a Twitter Feed, or a controller that has an Action to accept some posted information from a form. Child Actions on Surface Controller will probably be primarily used for Child Action Macros in Umbraco v5.

Since Surface Controllers are plugins, this means that you can create a package that contains Surface Controllers to distribute whatever front-end functionality you like to Umbraco developers. Surface Controllers, just like Tree Controllers and Editor Controllers get automatically routed for you.

Creating a Surface Controller

Important convention: All Surface controller names MUST be suffixed with ‘SurfaceController’. For example, if you are creating a Surface Controller to display system a Twitter feed, you might call your controller: TwitterFeedSurfaceController. If you don’t follow this convention, you’re surface controller wont be routed.

The first step is to create a class that inherits from the base Surface Controller class:  Umbraco.Cms.Web.Surface.SurfaceController

The next step is to define some MVC Action’s to do whatever it is you’d like them to do. Here’s some examples:

  • Creating an action to partake in a Child Action Macro. To define this is very simple and follows the exact same MVC principles to creating a Child Action… just add a ChildActionOnlyAttribute to your action method:
[ChildActionOnly]
public ActionResult DisplayTwitterFeed()
  • Creating a child action to simply be used as a normal MVC child action which get rendered using @Html.Action or @Html.RenderAction
  • Create an action to handle some posted form data:
[HttpPost]
public ActionResult HandleMyFormSubmission(MyFormModel model) 
  • Maybe you’d like to track all links clicked on your page. You could use jquery to update all of your links on your page to point to your custom action URL with the real URL as a query string. Then your custom action will log the real link address and redirect the user to where they want to go.

Plugins vs Non-plugins

A Surface Controller ‘can’ be a plugin, meaning that you can create it as a plugin and distribute it as part of a package. However, if you are creating your own Umbraco website and do your development in Visual Studio like most of us, you don’t need to create a Surface Controller with a plugin definition and install it as part of a package, you can just define it locally just like a controller in a normal MVC project. If you do want to ship your Surface Controller as part of a package then you must attribute your Surface Controller with the SurfaceAttribute, and give it an Id. If you don’t do this then Umbraco will detect that its loading a Surface Controller plugin without an Id and throw an exception.

As a plugin

Standard practice for creating any kind of controller is to put your controllers in the ‘Controllers’ folder (this is not mandatory but a simple convention to follow). So If you’ve created a new project in Visual Studio, you’d create a folder called ‘Controllers’, then create your Surface Controller class with the SurfaceAttribute and an Id:

using System.Web.Mvc;
using Umbraco.Cms.Web.Context;
using Umbraco.Cms.Web.Surface;
using Umbraco.Framework;

namespace MyProject.Controllers
{
    [Surface("98625300-6DF0-41AF-A432-83BD0232815A")]
    public class TwitterFeedSurfaceController : SurfaceController
    {

    }
}

Because this Surface Controller is a plugin, you’ll need to attribute your project assembly (just like when creating Trees or Editor plugins). You can declare this in any of your classes or in the AssemblyInfo.cs file.

[assembly: AssemblyContainsPlugins]

As a locally declared Surface Controller

This is pretty much identical to the above but you don’t have to include the SurfaceAttribute or attribute your assembly. If you’ve got an Umbraco v5 website that you’re working on you should just create a ~/Controllers folder to put your controller in, just as if you were creating a normal MVC project. Then you can create your Surface Controller:

using System.Web.Mvc;
using Umbraco.Cms.Web.Context;
using Umbraco.Cms.Web.Surface;
using Umbraco.Framework;

namespace MyProject.Controllers
{
    public class TwitterFeedSurfaceController : SurfaceController
    {

    }
}

Using a Surface Controller

The usage of a Surface Controller really depends on what you’ve created your surface controller to do. Probably the 3 main ways to use them will be:

  • Create a ChildAction Macro by using the Macro UI in the back office and selecting a child action that you’ve declared on your Surface Controller, then render the macro in your template or inline in the WYSIWYG editor.
  • Directly render a child action declared on your Surface Controller by using @Html.Action or @Html.RenderAction
  • Create an Html form to post data to an action on your Surface Controller using @Html.BeginUmbracoForm (more on this in the next blog post!)

Umbraco Jupiter Plugins - Part 4 - Editors

September 27, 2011 07:56

This is the fourth blog post in a series of posts relating to building plugins for Umbraco v5 (Jupiter). This post will show you how to get started with building an editor. An Editor is the term used to express the editing pane on the right hand side of the back-office. Examples include: the content editor, media editor, document type editor, script editor, etc..

Related Posts:

  1. Umbraco Jupiter Plugins – Part 1
  2. Umbraco Jupiter Plugins – Part 2 – Routing
  3. Umbraco Jupiter Pluings – Part 3 – Trees

Disclaimer

This post is about developing for Umbraco v5 (Jupiter) which at the time of this post is still under development. The technical details described below may change by the time Umbraco Jupiter is released. If you have feedback on the technical implementation details, please comment below.

Defining an Editor

An Editor in Umbraco v5 is the combination of: An MVC Controller, View(s), JavaScript and CSS. The first step to creating an Editor is to create a class that inherits from the Umbraco base editor class: Umbraco.Cms.Web.Editors.StandardEditorController. 

The next step is to register this editor as an editor plugin. To do this you just need to add an attribute to your class such as:

[Editor("ADD307B3-A5F9-4A89-ADAC-72289A5943FF")]

The mandatory parameter passed to this attribute is the editor plugin ID (this MUST be unique so ensure you generated a new GUID for every single one of your plugins).

The next thing you’ll need to do to ensure your editor plugin is found and loaded is to ‘advertise’ that your assembly contains a plugin. To do this, just edit your assembly’s AssemblyInfo.cs file and add the following attribute:

[assembly: AssemblyContainsPlugins]

Creating an Editor

Important convention: All Editor controller names MUST be suffixed with ‘EditorController’. For example, if you are creating an editor to display system information, you might call your Editor: SystemInfoEditorController. If you don’t follow this convention, you’re editor controller wont be routed.

When creating an Editor there are a few base classes to choose from. Generally however, you should inherit from: Umbraco.Cms.Web.Editors.StandardEditorController. The other base classes and their hierarchy are as follows:

  • Umbraco.Cms.Web.Mvc.Controllers.BackOffice.SecuredBackOfficeController
    • Umbraco.Cms.Web.Editors.BaseEditorController
      • Umbraco.Cms.Web.Editors.DashboardEditorController
        • Umbraco.Cms.Web.Editors.StandardEditorController

When inheriting from any of the base classes above, you will be required to create a constructor accepting an parameter of type: IBackOfficeRequestContext :

[Editor("ADD307B3-A5F9-4A89-ADAC-72289A5943FF")]
public class MyEditorController : StandardEditorController
{
    public MyEditorController(IBackOfficeRequestContext requestContext)
        : base(requestContext)
    {
    }        
}

The StandardEditorController has an abstract method: Edit(HiveId id) that needs to be implemented (the abstract Edit Action is marked as [HttpGet])

[Editor("ADD307B3-A5F9-4A89-ADAC-72289A5943FF")]
public class MyEditorController : StandardEditorController
{
    public MyEditorController(IBackOfficeRequestContext requestContext)
        : base(requestContext)
    {
    }
        
    public override ActionResult Edit(HiveId id)
    {
        return View();
    }
}

Most Editors will be displaying a view to edit data based on a HiveId which is the unique identifier type for pretty much all data in Umbraco 5. If you are writing an editor to edit data in a custom Hive provider, then this will work seamlessly for you. Even if you are creating an editor for data that you aren’t writing a custom Hive provider for, you can still use HiveId as a unique identifier since it has support for wrapping Guid, Int and String Id types. If however you decide that HiveId isn’t for you, then you can inherit from one of the other editor base classes that doesn’t have the abstract Edit method attached to it and create your own Actions with your own parameters.

The above Edit Action simply returns a view without a model to be rendered. At this point, you’ll need to know where your view should be stored which has everything to do with MVC Areas or embedding views.

MVC Areas & Jupiter Packages

In a previous post we talk about how packages in v5 are actually registered as their own MVC Area. All packages get installed to the following location: ~/App_Plugins/Packages/{YourPackageName} . If you aren’t embedding your views, then they should be stored inside of your package folder. Each plugin type has a specific view folder name that your views should be stored in:

  • Editor views & partial views:
    • ~/App_Plugins/Packages/{YourPackageName}/Editors/Views/ {EditorControllerName}/{ViewName}.cshtml
    • ~/App_Plugins/Packages/{YourPackageName}/Editors/Views/Shared/ {ViewName}.cshtml
  • Property Editor partial views:
    • ~/App_Plugins/Packages/{YourPackageName}/PropertyEditors/Views/Shared/ {ViewName}.cshtml
  • Dashboard partial views:
    • ~/App_Plugins/Packages/{YourPackageName}/Dashboards/Views/ {ViewName}.cshtml
  • Rendering (front-end) partial views:
    • ~/App_Plugins/Packages/{YourPackageName}/Views/Partial/ {ViewName}.cshtml

So with the controller created above, I would have a view in the following location:

~/App_Plugins/{MyPackageName}/Editors/Views/MyEditor/Edit.cshtml

NOTE: The package name folder will be created when installing your NuGet package and will be based on your NuGet package name and version assigned.

Embedding views

Many of the views shipped with v5 are embedded which helps to reduce the number of actual files that are shipped. This is also handy if you don’t want to give the ability for people to change what’s in your markup.

Embedding a view is really easy:

  • Create a Razor (.cshtml) view in your Package’s project
  • View the Properties for this file and choose ‘Embedded Resource’ as the ‘Build Action’

Now to use the embedded view we use the following syntax:

[Editor("ADD307B3-A5F9-4A89-ADAC-72289A5943FF")]
public class MyEditorController : StandardEditorController
{
    public MyEditorController(IBackOfficeRequestContext requestContext)
        : base(requestContext)
    {
    }
        
    public override ActionResult Edit(HiveId id)
    {
        return View(EmbeddedViewPath.Create("MyProject.Editors.Views.Edit.cshtml"));
    }
}

Its important to get the correct path to your view file. In this instance, my view’s path in my project is: MyProject.Editors.Views.Edit.cshtml

Displaying your Editor

Most of the time an editor is displayed by clicking on a node in the tree or by accessing a context menu item. In a previous post about creating trees there was a method to create a tree node:

protected override UmbracoTreeResult GetTreeData(HiveEntityUri id, FormCollection queryStrings)
{
    NodeCollection.Add(
        CreateTreeNode(id, null, "My only node", string.Empty, false));
    return UmbracoTree();
}

This simply created a tree node that had no editor URL but now that we have an editor, I’ll update the code to click through to my Edit Action:

protected override UmbracoTreeResult GetTreeData(HiveId id, FormCollection queryStrings)
{
    NodeCollection.Add(
        CreateTreeNode(id, null, "My only node",
        Url.GetEditorUrl("MyEditor", id, new Guid("ADD307B3-A5F9-4A89-ADAC-72289A5943FF")),
        false));
    return UmbracoTree();
}
GetEditorUrl is an extension method of UrlHelper which has a few overloads for generating an Editor’s Url. In this case we are passing in the Editor’s name and Id with the Id of the current node being rendered in the tree.

When the node is clicked it will now link to the Edit Action of the MyEditor Controller.

Umbraco Jupiter Plugins - Part 2 - Routing

May 11, 2011 10:26

This is the second blog post in a series of posts relating to building plugins for Umbraco v5 (Jupiter).

Related Posts:

  1. Umbraco Jupiter Plugins – Part 1

Disclaimer

This post is about developing for Umbraco v5 (Jupiter) which at the time of this post is still under development. The technical details described below may change by the time Umbraco Jupiter is released. If you have feedback on the technical implementation details, please comment below.

Routing & URLs

As mentioned in the previous post Umbraco Jupiter will consist of many types of plugins, and of those plugins many of them exist as MVC Controllers.  Each controller has an Action which a URL is routed to, this means that each Controller plugin in Jupiter requires it’s own unique URLs. The good news is that you as a package developer need not worry about managing these URLs and routes, Jupiter will conveniently do all of this for you.

Packages & Areas

My previous post mentioned that a ‘Package’ in Jupiter is a collection of ‘Plugins’ and as it turns out, Plugins can’t really function unless they are part of a Package. In it’s simplest form, a Package in v5 is a folder which contains Plugins that exists in the ~/Plugins/Packages sub folder. The folder name of the package becomes very important because it is used in setting up the routes to  create the unique URLs which map to the MVC Controller plugins. Package developers should be aware that they should name their folder to something that is reasonably unique so it doesn’t overlap with other Package folder names. During package installation, Jupiter will check for uniqueness in Package folder names to ensure there is no overlap (there will be an entirely separate post on how to create deployment packages and how to install them).

Here’s a quick example: If I have a Package that contains a Tree plugin called TestTree (which is in fact an MVC Controller) and I’ve called my Package folder ‘Shazwazza’, which exists at ~/Plugins/Packages/Shazwazza then the URL to return the JSON for the tree is: http://localhost/Umbraco/Shazwazza/Trees/TestTree/Index 

Similarly, if I have a Editor plugin called TestEditor with an action called Edit, then a URL to render the Edit Action is:

http://localhost/Umbraco/Shazwazza/Editors/TestEditor/Edit

If you’ve worked with MVC, you’ll probably know what an MVC Area is. The way that Jupiter creates the routes for Packages/Plugins is by creating an MVC Area for each Package. This is how it deals with the probability that different Package developers may create MVC Controllers with the same name. MVC routes are generally based just on a Controller name and an Action name which wouldn’t really work for us because there’s bound to be overlap amongst Package developers, so by creating an Area for each Package the route becomes unique to a combination of Controller name, Action name and Area name.  MVC also determines where to look for Views based on Area name which solves another issue of multiple Packages installed with the same View names.

Whats next?

In the coming blog posts I’ll talk about

  • how plugins are installed and loaded
  • how and where the Views are stored that the plugins reference
  • how to create all of the different types of plugins

Code Garden 2011

I’ll be doing a talk on Plugins for Umbraco Jupiter at Code Garden 2011 this year which will go in to a lot more detail than these blog posts. If you are attending Code Garden already, then hopefully this series will give you a head start on Umbraco v5. If you haven’t got your tickets to Code Garden yet, what are you waiting for?! We have so much information to share with you :)