<![CDATA[Shazwazza]]> <![CDATA[Admin]]> <![CDATA[ASP.Net MVC]]> <![CDATA[Bits & Pieces]]> <![CDATA[Client Dependency]]> <![CDATA[Examine]]> <![CDATA[Servers, Hosting, etc...]]> <![CDATA[Umbraco]]> <![CDATA[Web Development]]> <![CDATA[Using IoC with Umbraco & MVC]]> The question was asked on my post yesterday about the upcoming Umbraco 4.10.0 release with MVC support and whether it is possible to use IoC/Dependency Injection with our implementation. The answer is definitely yes!

One of the decisions we’ve made for the code of Umbraco is to not use IoC in the core. This is not because we don’t like IoC (in fact I absolutely love it) but more because things start to get really messy when not 100% of your developers understand it and use it properly. Since Umbraco is open source there are developers from many walks of life committing code to the core and we’d rather not force a programming pattern on them. Additionally, if some developers don’t fully grasp this pattern this leads to strange and inconsistent code and even worse if developers don’t understand this pattern then sometimes IoC can be very difficult to debug.

This ultimately means things are better for you since we won’t get in the way with whatever IoC framework you choose.

Which frameworks can i use?

Theoretically you can use whatever IoC framework that you’d like, though I haven’t tested or even tried most of them I’m assuming if they are reasonable frameworks that work with MVC then you should be fine. I’m an Autofac fan and to be honest I’ve only dabbled in other frameworks so all examples in this post and documentation are based on Autofac. Since we don’t use any IoC, it also means that we are not specifying a DependencyResolver so you are free to set this to whatever you like (I’d assume that most IoC frameworks would integrate with MVC via the DependencyResolver).

How do i do it?

I chucked up some docs on github here which I’ll basically just reiterate on this post again with some more points. Assuming that you construct your IoC container in your global.asax, the first thing you’ll have to do is to create this class and make sure it inherits from the Umbraco one (otherwise nothing will work). Then just override OnApplicationStarted and build up your container. Here’s an example (using Autofac):

/// <summary>
/// The global.asax class
/// </summary>
public class MyApplication : Umbraco.Web.UmbracoApplication
{
    protected override void OnApplicationStarted(object sender, EventArgs e)
    {
        base.OnApplicationStarted(sender, e);

        var builder = new ContainerBuilder();

        //register all controllers found in this assembly
        builder.RegisterControllers(typeof(MyApplication).Assembly);

        //add custom class to the container as Transient instance
        builder.RegisterType<MyAwesomeContext>();

        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    }
}

Notice that I’ve also registered a custom class called MyAwesomeContext in to my container, this is just to show you that IoC is working. Of course you can do whatever you like with your own container :) Here’s the class:

public class MyAwesomeContext
{
    public MyAwesomeContext()
    {
        MyId = Guid.NewGuid();
    }
    public Guid MyId { get; private set; }
}

Next we’ll whip up a custom controller to hijack all routes for any content item that is of a Document Type called ‘Home’ (there’s documentation on github about hijacking routes too):

public class HomeController : RenderMvcController
{
    private readonly MyAwesomeContext _myAwesome;

    public HomeController(MyAwesomeContext myAwesome)
    {
        _myAwesome = myAwesome;
    }

    public override ActionResult Index(Umbraco.Web.Models.RenderModel model)
    {
        //get the current template name
        var template = this.ControllerContext.RouteData.Values["action"].ToString();
        //return the view with the model as the id of the custom class
        return View(template, _myAwesome.MyId);
    }
}

In the above controller, a new instance of MyAwesomeContext will be injected into the constructor, in the Index action we’re going to return the view that matches the currently routed template and set the model of the view to the id of the custom MyAwesomeContext object (This is just an example, you’d probably do something much more useful than this).

We can also do something similar with SurfaceControllers (or any controller you like):

public class MyTestSurfaceController : SurfaceController
{
    private readonly MyAwesomeContext _myAwesome;

    public MyTestSurfaceController(MyAwesomeContext myAwesome)
    {
        _myAwesome = myAwesome;
    }

    [ChildActionOnly]
    public ActionResult HelloWorld()
    {
        return Content("Hello World! Here is my id " + _myAwesome.MyId);
    }
}

That’s it?

Yup, these are just examples of creating controllers with IoC, the actual IoC setup is super easy and should pretty much work out of the box with whatever IoC framework you choose. However, you should probably read the ‘Things to note’ in the documentation in case your IoC engine of choice does something wacky with the controller factory.

]]>
<![CDATA[re: Using IoC with Umbraco & MVC]]> <![CDATA[re: Using IoC with Umbraco & MVC]]> <![CDATA[re: Using IoC with Umbraco & MVC]]> <![CDATA[re: Using IoC with Umbraco & MVC]]> <![CDATA[re: Using IoC with Umbraco & MVC]]>
<![CDATA[Native MVC support in Umbraco coming very soon!]]> Its been a while since writing a blog post! … but that’s only because I can never find the time since I’m still gallivanting around the globe :P

But this post is about something very exciting, and I’m sure most of you that are reading this already know that with the upcoming Umbraco 4.10.0 release (currently in Beta and downloadable here) we are natively supporting ASP.Net MVC! What’s more is that I’ve tried to document as much as I could on our GitHub docs. Once my pull request is completed the docs will all be available on the main site but until then you can see them on my fork here.

So where to begin? Well, I’m going to try to keep this really short and sweet because I’m hoping you can find most of the info that you’ll want in the documentation.

What is supported?

Everything that you can do in MVC you will be able to do in Umbraco’s MVC implementation. Anything from Partial Views, Child Actions, form submissions, data annotations, client validation to Surface Controllers, custom routes and hijacking Umbraco routes.  If you have used Razor macros before, we support a very similar syntax but it is not 100% the same. We support most of the dynamic querying that you use in Razor macros with the same syntax but to access the dynamic model is slightly different. What is crazy awesome super cool though is that we support a strongly typed query structure!! :) So yes, you can do strongly typed Linq queries with intellisense, no problemo!

Still using Web forms? not a problem, you can have both Web forms and MVC engines running in tandem on your Umbraco site. However, a config setting will set a default rendering engine which will determine whether Web forms master pages or MVC views are created in the back office.

What is not supported (yet)

There’s a few things in this release that we’ve had to push to 4.11.0 due to time constraints. They include: Better tooling support for the View editors in the back office, Partial View Macros and Child Action Macros. Though once you start using this MVC version you’ll quickly discover that the need for macros is pretty small. Perhaps people use macros in different ways but for the most part with the way that MVC works I would probably only use macros for rendering macro content in the WYSIWYG editor.

We support rendering any macros in MVC so you can even render your XSLT macros in your views, but issues will arise if you have User Control or Web form control macros that contain form elements. You will still be able to render these macros but any post backs will not work, and will most likely cause a YSOD. Unfortunately due to the vast differences between how Web forms and MVC work in ASP.Net this is something that we cannot support. The good news is that creating forms in MVC is super easy and makes a whole lot more sense than Web forms…. you can even have more than one <form> element on a page, who’d have thought :P

Strongly typed queries

You can find the documentation for this here but I just wanted to point out some of the differences between the strongly typed syntax and the dynamic syntax. First, in your view you have two properties:

  • @Model.Content = the strongly typed model for your Umbraco view which is of type: Umbraco.Core.Models.IPublishedContent
  • @CurrentPage = the dynamic model representing the current page, this is very very similar to the @Model property in Razor macros

An example is to get the current page’s children that are visible, here’s the syntax for both (and of course since the @CurrentPage is dynamic, you will not get intellisense):

//dynamic access
@CurrentPage.Children.Where("Visible")

//strongly typed access
@Model.Content.Children.Where(x => x.IsVisible())

There are also some queries that are just not (yet) possible in the dynamic query structure. In order to get some complex queries to work with dynamic linq, we need to code these in to the parser to create the expression tree. The parser could probably do with more TLC to support things like this but IMHO, we’re just better off using the strongly typed way instead (plus its probably a much faster execution). I’ve listed this as an example in the docs but will use it here again:

//This example gets the top level ancestor for the current node, and then gets 
//the first node found that contains "1173" in the array of comma delimited
//values found in a property called 'selectedNodes'.
//NOTE: This is one of the edge cases where this doesn't work with dynamic execution but the
//syntax has been listed here to show you that its much easier to use the strongly typed query
//instead

//dynamic access
var paramVals = new Dictionary<string, object> {{"splitTerm", new char[] {','}}, {"searchId", "1173"}};
var result = @CurrentPage.Ancestors().OrderBy("level")
.Single()
.Descendants()
.Where("selectedNodes != null && selectedNodes != String.Empty && selectedNodes.Split(splitTerm).Contains(searchId)", paramVals)
.FirstOrDefault();

//strongly typed
var result = @Model.Content.Ancestors().OrderBy(x => x.Level)
.Single()
.Descendants()
.FirstOrDefault(x => x.GetPropertyValue("selectedNodes", "").Split(',').Contains("1173"));

IMHO i much prefer the strongly typed syntax but it’s up to you to decide since we support both structures.

UmbracoHelper

Another class we’ve introduced is called the Umbraco.Web.UmbracoHelper which is accessible on your views by using the @Umbraco syntax and is also accessible on any SurfaceController. This class contains a ton of handy methods, it is basically the ‘new’ Umbraco ‘library’ class (you know that static one that has a lower case ‘l’ :P ) Of course the ‘library’ class will still be around and you can still use it in your views… but you shouldn’t! This new helper class should contain all of the methods that you need from querying content/media by ids, rendering macros and rendering field content, to stripping the html from a string. The library class was designed for use in Xslt where everything from c# wasn’t natively given to you, now with Razor views you have the entire world of c# at your fingertips. So you’ll notice things like the date formatting functions that were on ‘library’ are not on the UmbracoHelper, and that is because you can just use the regular c# way. Though, if you feel inclined that these methods should be on UmbracoHelper, another great thing is that this is not a static class so you can add as many extension methods as you like.  I’d list all of the methods out here but I said I’d keep it short, your best bet currently is to just have a look at the class in the source code, or just see what great stuff shows up in intellisense in VS.

UmbracoContext

Though we did have another UmbracoContext class, this one is the new cooler one and the old one has been marked as obsolete. This new one’s full name is Umbraco.Web.UmbracoContext and it is a singleton so you can access it by UmbracoContext.Current but normally you shouldn’t have to access it by it’s singleton because it is available in all of your views and SurfaceControllers as a property. For example, to access the UmbracoContext in your view you simply use @UmbracoContext. This class exposes some handy properties like: UmbracoUser, PageId, IsDebug, etc…

Testing

If you are interested in MVC and Umbraco, it would be really really appreciated for you to take the time to download the beta, the latest nightlies or source code and give it a shot. Hopefully the docs are enough to get you up and running and if you run into any troubles please log your issues on the tracker. If you have any question, comments, etc… about the source code we’d love to hear from you on the mail list.

Pete will be putting up an MVC getting started post on the Umbraco blog real soon, so watch this space!

Adios!

]]>
<![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]> <![CDATA[re: Native MVC support in Umbraco coming very soon!]]>
<![CDATA[MVC in Umbraco v4]]> After the announcement of discontinuing Umbraco v5 development during this years Code Garden 2012 conference, the biggest question seemed to be: What will happen with ASP.Net MVC and Umbraco. We held an open space session regarding this question where we asked 2 questions: “Is an MVC implementation in Umbraco important to have for the front end?” and “Is an MVC implementation important to have for the back office?”. There were quite a few people who attended this session and I think 100% of people raised their hands in answer to the first question and only 1 person raised their hands for the second answer.  I think this result was expected since most Umbraco developers simply wish to use MVC in their own development on the front-end and want the Umbraco back office to keep working with all of the great packages already created for it.

There was a considerable amount of knowledge gained in creating v5 and of course we will incorporate much of this knowledge into v4… starting real soon! I decided to create a package for Umbraco v4 which enables a native MVC front end which was demo’d during the Code Garden package competition and is available right now!  It turns out that creating this didn’t take much time at all, in fact I created it during the 2nd day of the conference. The reason this was reasonable easy was because we had all of this already built for v5 so it was a matter of taking this knowledge and code and applying it to v4.

So if you are like many other devs and really want Umbraco to route to a native MVC front end then you can give this package a try, its called umbraMVCo. Please be warned that I have not tested this very much, but also know that its just using the tried and tested v4 api’s to do the routing so I’m assuming it will ‘just work’ … though I’m sure you guys will find some bugs I haven’t yet :) There’s also a readme file on the downloads page which explains how to install it, and what settings/servers that I know it works with.

What’s also really cool is this code completely supports Hijacking Umbraco Routes!

Download/Source

You can download the package and readme files here

https://bitbucket.org/Shandem/umbramvco/downloads

Ensure that you read the readme file, it contains some very important information including installation instructions!

The source can be found here:

https://bitbucket.org/Shandem/umbramvco/src

If you come across issues with this please log issues here: https://bitbucket.org/Shandem/umbramvco/issues . The source isn’t really complicated or anything though so you should be able to identify the reason for an issue if you come across it.

What’s next?

So will MVC be coming to v4… Yes indeed. We will also support routing to either WebForms or MVC and we’ll support this by having a flag on the document type to choose which rendering engine to use. We’ve got a few things to do in v4 regarding how routing works to do this nicely/properly but the end result will be pretty much the same as what this package enables. All of those cool MVC things that you liked in v5 like SurfaceControllers will be coming to v4 as well, we will still support Child Action and Partial View macros. Another cool thing is that we should be able to support Xslt and UserControl macros in MVC as well (though any post backs will definitely not work).

So even though the development of v5 has been discontinued, a ton of the concepts that you liked about it will in fact be ported to v4.

]]>
<![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[re: MVC in Umbraco v4]]> <![CDATA[Pingback from blog.cwa.me.uk The Morning Brew - Chris Alcock » The Morning Brew #1126]]> <![CDATA[Pingback from awoni.net Umbraco 4 と ASP.NET MVC]]>
<![CDATA[Taming the BuildManager, ASP.Net Temp files and AppDomain restarts]]> I’ve recently had to do a bunch of research in to the BuildManager and how it deals with caching assemblies since my involvement with creating an ASP.Net plugin engine. Many times people will attempt to restart their AppDomain by ‘bumping’ their web.config files, meaning adding a space character or carriage return and then saving it. Sometimes you may have noticed that this does not always restart your AppDomain the way you’d expect and some of the new types you’d expect to have loaded in your AppDomain simply aren’t there. This situation has cropped up a few times when using the plugin engine that we have built in to Umbraco v5 and some people have resorted to manually clearing out their ASP.Net temp files and then forcing an IIS Restart, but this is hardly ideal. The good news is that we do have control over how these assemblies get refreshed, in fact the BuildManager reloads/refreshes/clears assemblies in different ways depending on how the AppDomain is restarted.

The hash.web file

An important step during the BuildManager initialization phase is a method call to BuildManager.CheckTopLevelFilesUpToDate which does some interesting things. First it checks if a special hash value is on disk and is not zero. You may have noticed a file in your ASP.Net temp files: /hash/hash.web and it will contain a value such as: 4f34227133de5346. This value represents a unique hash of many different combined objects that the BuildManager monitors. If this file exists and the value can be parsed properly then the BuildManager will call: diskCache.RemoveOldTempFiles(); What this does is the following:

  • removes the CodeGen temp resource folder
  • removes temp files that have been saved during CodeGen such as *.cs
  • removes the special .delete files and their associated original files which have been created when shutting down the app pool and when the .dll files cannot be removed (due to file locking)

Creating the hash value

The next step is to create this hash value based on the current objects in the AppDomain. This is done using an internal utility class in the .Net Framework called: HashCodeCombiner (pretty much everything that the BuildManager references is marked Internal! ). The process combines the following object values to create the hash (I’ve added in parenthesis the actual properties the BuildManager references):

  • the app's physical path, in case it changes (HttpRuntime.AppDomainAppPathInternal)
  • System.Web.dll (typeof(HttpRuntime).Module.FullyQualifiedName)
  • machine.config file name (HttpConfigurationSystem.MachineConfigurationFilePath)
  • root web.config file name, please note that this is not your web apps web.config (HttpConfigurationSystem.RootWebConfigurationFilePath)
  • the hash of the <compilation> section (compConfig.RecompilationHash)
  • the hash of the system.web/profile section (profileSection.RecompilationHash)
  • the file encoding set in config (appConfig.Globalization.FileEncoding)
  • the <trust> config section (appConfig.Trust.Level & appConfig.Trust.OriginUrl)
  • whether profile is enabled (ProfileManager.Enabled)
  • whether we are precompiling with debug info (but who precompiles :) (PrecompilingWithDebugInfo)

Then we do a check for something I didn’t know existed called Optimize Compilations which will not actual affect the hash file value for the following if it is set to true (by default is is false):

  • the ‘bin’ folder (HttpRuntime.BinDirectoryInternal)
  • App_WebReferences (HttpRuntime.WebRefDirectoryVirtualPath)
  • App_GlobalResources  (HttpRuntime.ResourcesDirectoryVirtualPath)
  • App_Code (HttpRuntime.CodeDirectoryVirtualPath)
  • Global.asax (GlobalAsaxVirtualPath)

Refreshing the ASP.Net temp files (CodeGen files)

The last step of this process is to check if the persisted hash value in the hash.web file equals the generated hash value from the above process. If they do not match then a call is made to diskCache.RemoveAllCodegenFiles(); which will:

  • clear all codegen files, removes all files in folders but not the folders themselves,
  • removes all root level files except for temp files that are generated such as .cs files, etc...

This essentially clears your ASP.Net temp files completely, including the MVC controller cache file, etc…

Then the BuildManager simply resaves this calculated has back to the hash.web file.

What is the best way to restart your AppDomain?

There is really no ‘best’ way, it just depends on your needs. If you simply want to restart your AppDomain and not have the overhead of having your app recompile all of your views and other CodeGen classes then it’s best that you simply ‘bump’ your web.config by just adding a space, carriage return or whatever. As you can see above the hash value is not dependant on your local web.config file’s definition (timestamp, etc…). However, the hash value is dependent on some other stuff in your apps configuration such as the <compilation> section, system.web/profile section, the file encoding configured, and the <trust> section. If you update any value in any of these sections in your web.config it will force the BuildManager to clear all cached CodeGen files which is the same as clearing your ASP.Net temp files.

So long as you don’t have optimizeCompilations set to true, then the easiest way to clear your CodeGen files is to simply add a space or carriage return to your global.asax file or modify something in the 4 other places that the BuildManager checks locally: App_Code, App_GlobalResources, App_WebResources, or modify/add/remove a file in your bin folder.

How does this affect the ASP.Net plugin engine?

Firstly, i need to update that post as the code in the plugin engine has changed quite a bit but you can find the latest in the Umbraco source code on CodePlex. With the above knowledge its easy to clear out any stale plugins by perhaps bumping your global.asax file, however this is still not an ideal process. With the research I’ve done in to the BuildManager I’ve borrowed some concepts from it and learned of a special “.delete” file extension that the BuildManager looks for during AppDomain restarts. With this new info, I’ve already committed some new changes to the PluginManager so that you shouldn’t need to worry about stale plugin DLLs.

]]>
<![CDATA[re: Taming the BuildManager, ASP.Net Temp files and AppDomain restarts]]> <![CDATA[re: Taming the BuildManager, ASP.Net Temp files and AppDomain restarts]]>
<![CDATA[Hijacking Umbraco routes]]> DISCLAIMER!

This blog post relates to the latest source code of Umbraco v5 and will not work in Umbraco 5.0.0. Unfortunately due to my own mistakes which I take full credit for (#h5is) in fixing a last minute bug in 5.0.0 I actually broke this functionality for the release. So the following blog post relates to upcoming releases of Umbraco 5.x or if you are using the latest source code in Mercurial.

By default all of the front end routing is executed via the UmbracoController Index Action which should work fine for most people. However, in some cases people may want complete control over this execution and may  want their own Action to execute. Some reasons for this may be: to control exactly how views are rendered, custom/granular security for certain pages/templates or to be able to execute any custom code in the controller that renders the front end. The good news is that this is completely possible, in fact this was one of the first features implemented in V5 all the way back in 2010!

This process is all about convention and it's really simple. It's easiest to demonstrate with an example : let's say you have a document type called 'Home'.  You can create a custom locally declared controller in your MVC web project called 'HomeController' and ensure that it inherits from Umbraco.Cms.Web.Mvc.Controllers.UmbracoController and now all pages that are of document type 'Home' will be routed through your custom controller! Pretty easy right :-)

OK so let's see how we can extend this concept. In order for you to run some code in your controller you'll need to override the Index Action. Here’s a quick example:

public class HomeController : UmbracoController
{
public override ActionResult Index(IUmbracoRenderModel model)
{
//Do some stuff here, the return the base method
return base.Index(model);
}
}

Now you can run any code that you want inside of that Action. To further extend this, we've also allowed routing to different Actions based on the Template that is being rendered. By default only the Index Action exists which will execute for all requests of the corresponding document type. However, if the template being rendered is called 'HomePage' and you have an Action on your controller called 'HomePage' then it will execute instead of the Index Action. As an example, say we have a Home Document Type which has 2 allowed Templates: ‘HomePage’ and ‘MobileHomePage’ and we only want to do some custom stuff for when the ‘MobileHomePage’ Template is executed:

public class HomeController : UmbracoController
{
public ActionResult MobileHomePage(IUmbracoRenderModel model)
{
//Do some stuff here, the return the base Index method
return base.Index(model);
}
}


So here's how the mapping works:

  • Document Type name = controller name
  • Template name = action name, but if no action matches or is not specified then the 'Index' action will be executed.

In the near future we will allow setting a custom default controller to execute for all requests instead of the standard UmbracoController. Currently you'd have to create a controller for every document type to have a customer controller execute for all requests.

There's probably a ton of uses for hijacking an Umbraco request that we haven't thought of yet. Now that you know how to do it I'm sure plenty of new techniques will be invented.

Happy coding!  :)

]]>
<![CDATA[re: Hijacking Umbraco routes]]> <![CDATA[re: Hijacking Umbraco routes]]> <![CDATA[re: Hijacking Umbraco routes]]> <![CDATA[re: Hijacking Umbraco routes]]> <![CDATA[re: Hijacking Umbraco routes]]> <![CDATA[re: Hijacking Umbraco routes]]> <![CDATA[re: Hijacking Umbraco routes]]> <![CDATA[re: Hijacking Umbraco routes]]> <![CDATA[re: Hijacking Umbraco routes]]> <![CDATA[re: Hijacking Umbraco routes]]> <![CDATA[re: Hijacking Umbraco routes]]> <![CDATA[re: Hijacking Umbraco routes]]> <![CDATA[re: Hijacking Umbraco routes]]> <![CDATA[MVC in Umbraco v4 MVC in Umbraco v4]]> <![CDATA[Pingback from awoni.net Umbraco 4 と ASP.NET MVC]]>
<![CDATA[Registering custom components in IoC for Umbraco 5 plugins]]> Sometimes you might need to add some of your own components to the IoC container in Umbraco 5 for your plugins to function. We’ve made this extremely easy to do and it only requires 2 steps:

Create a custom class that implements Umbraco.Framework.DependencyManagement.IDependencyDemandBuilder . Ensure that this class does not have any constructor parameters otherwise it will not work. There’s only one method to implement and you can use the containerBuilder parameter to add stuff to the IoC container:

void Build(IContainerBuilder containerBuilder, IBuilderContext context);


Next you need to attribute your plugin (i.e. Tree, Editor, Menu Item, Property Editor, Surface Controller, etc….) to tell it which ‘Demand Builder’ to use. Easiest to explain with an example:

[DemandsDependencies(typeof(MyCustomBuilder))]
[Tree("4883C970-2499-488E-A963-5204F6C6F840", "My Tree")]
public class MyCustomTree : TreeController

The above code will ensure that the ‘Demand Builder’ of type MyCustomBuilder will be executed when this plugin is loaded

Thats it! Now you can add anything you need to the IoC container if you require this for your plugin.

]]>
<![CDATA[re: Registering custom components in IoC for Umbraco 5 plugins]]> <![CDATA[re: Registering custom components in IoC for Umbraco 5 plugins]]> <![CDATA[re: Registering custom components in IoC for Umbraco 5 plugins]]> <![CDATA[re: Registering custom components in IoC for Umbraco 5 plugins]]> <![CDATA[re: Registering custom components in IoC for Umbraco 5 plugins]]> <![CDATA[re: Registering custom components in IoC for Umbraco 5 plugins]]> <![CDATA[re: Registering custom components in IoC for Umbraco 5 plugins]]> <![CDATA[re: Registering custom components in IoC for Umbraco 5 plugins]]> <![CDATA[re: Registering custom components in IoC for Umbraco 5 plugins]]> <![CDATA[re: Registering custom components in IoC for Umbraco 5 plugins]]> <![CDATA[re: Registering custom components in IoC for Umbraco 5 plugins]]> <![CDATA[re: Registering custom components in IoC for Umbraco 5 plugins]]> <![CDATA[re: Registering custom components in IoC for Umbraco 5 plugins]]>
<![CDATA[Umbraco v5 Surface Controller Forms]]> This post will show you how to create a form in Umbraco v5 using Surface Controllers. The information in this post assumes that you are familiar with Surface Controllers (see this previous post if not) and with creating forms in ASP.Net MVC.

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.

Create a model

The easiest way to create a form in MVC is to create a model that represents your form. This isn’t mandatory but then you’ll have to use some old school techniques like getting posted values directly from the HttpRequest object.

An example could be:

namespace MySite.Models
{
    public class MyTestModel
    {
        [Required]
        public string Name { get; set; }

        [Required]
        [Range(18,30)]
        public int Age { get; set; }        
    }
}

Create a Surface Controller

For this example we’ll assume that we’re creating a locally declared Surface Controller (not a plugin, see the previous post for full details).

Some code first and explanation after:

namespace MySite.Controllers
{   
    public class MySurfaceController : SurfaceController
    {
        [HttpPost] 
        public ActionResult HandleFormSubmit(
            [Bind(Prefix = "MyTestForm")]
            MyTestModel model)
        {
            if (!ModelState.IsValid)
            {
                return CurrentUmbracoPage();
            }            
            
            //do stuff here with the data in the model... send
            // an email, or insert into db, etc...
            
            return RedirectToUmbracoPage(
                new HiveId(
                    new Guid("00000000000000000000000000001049")));
        }
    }
}

Lets break down some parts of the above Controller code:

Namespace: Generally you’ll put your locally declared controllers in the ~/Controllers folder, the above namespace reflects this.

Class: The Surface Controller class is suffixed with the term ‘SurfaceController’. This is a required convention (as per the previous post), without that suffix, the controller will not get routed.

[Bind] attribute: In the code below you’ll see that we are creating the editor with a ‘prefix’ called ‘MyTestForm’. This ensures that each input element on the form will get its name prefixed with this value. For example:

<input type="text" name="MyTestForm.Name" />

This is a recommended practice however it is optional. If you don’t prefix your form controls then you don’t need to use the [Bind] attribute. Here’s a few reasons why this is a recommended practice:

  1. Without the prefix, If there is more than 1 form rendered on your webpage and both are using the MVC validation summary, then both validation summaries will display the errors for both forms. When there is a prefix you can tell the validation summary to only display errors for the form with the specified prefix.
  2. The MVC Html helpers will generate the html id for each element and without specifying a prefix and if you have more than 1 form rendered on your page you may end up with duplicate html element Ids.
  3. If you create a scaffolded form with a custom model object such as doing:

    @{ var someModel = new MyModel(); }
    @Html.EditorFor(x => someModel)

    then MVC will automatically prefix your input fields with ‘someModel’ . For some reason MVC does this when the model name isn’t exactly ‘Model’.

return CurrentUmbracoPage: This method is built in to the base SurfaceController class and simply returns the currently executing Umbraco page without a redirect to it which is generally what you want to do in order to display any validation errors.

return RedirectToUmbracoPage: This method is built in to the base SurfaceController class and performs a redirect to a Umbraco page given an Id which is generally what you want to do when a form submission is successful. (chances are that you wont have a page with a Guid id of 00000000000000000000000000001234…. this is just an example :)

NOTE: There is also a RedirectToCurrentUmbracoPage() method!

Rendering a form

There are a few ways to render a form:

  • Directly in your Umbraco template/view
  • Using a Partial View macro
  • Using a Child Action macro which renders a partial view

Regardless of which you use to render a form, the markup will be very similar. Similar to MVC’s @Html.BeginForm, we have an @Html.BeginUmbracoForm helper:

@{
    var formModel = new MySite.Models.MyTestModel();
}

@using(Html.BeginUmbracoForm("HandleFormSubmit", "MySurface"))
{
    @Html.ValidationSummary(prefix: "MyTestForm")
    @Html.EditorFor(x => formModel, "", "MyTestForm")
    <input type="submit"/>
}

Here’s the breakdown of the above mark-up:

Html.BeginUmbracoForm: A normal MVC form would simply use Html.BeginForm which will create an action attribute for the html form tag with a URL of your controller’s action. In Umbraco however, we want the URL to be posted to the same as the URL being rendered (post back), so the BeginUmbracoForm call handles this all for us. It will create a form tag with the URL of the currently rendered Umbraco node and add some custom hidden fields to your form containing the values of where the data will actually post to (your Surface Controller’s action). The Umbraco front-end route handler will take care of all of this for you.

The parameters passed in to BeginUmbracoForm will differ depending on if your Surface Controller is a plugin controller or a locally declared controller. In this example, its a locally declared controller so we just need to give it the action name and controller name. If its a plugin Surface Controller, you’ll need to give it the action and and the controller ID. There’s also a few overloads so that you can add additional html attributes to the rendered html form tag.

@Html.ValidationSummary: The native MVC ValidationSummary doesn’t let you target specific input tags via prefixes so we’ve created a ‘better’ one that does let you do that. In this example we’re telling the validation summary to only display errors for input values that are prefixed with “MyTestForm” which is real handy if you’re rendering a few forms on the same page and using a validation summary for each.

@Html.EditorFor: This is the native EditorFor method in MVC which lets you supply a prefix name which will be used for all of your input fields. The MVC methods for rendering individual input tags also have an overload to supply a prefix if you choose not to have it scaffold your form for you.

formModel: The above mark-up will scaffold the form for us based on the model that we created previously. This example creates an inline model object (formModel) to scaffold the form but if you had a strongly typed partial view with your model type, you could just as well use the view’s Model property.

And that’s pretty much it! Happy form making :)

]]>
<![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]> <![CDATA[re: Umbraco v5 Surface Controller Forms]]>
<![CDATA[Umbraco Jupiter Plugins - Part 5 - Surface Controllers]]> 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!)
]]>
<![CDATA[re: Umbraco Jupiter Plugins - Part 5 - Surface Controllers]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 5 - Surface Controllers]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 5 - Surface Controllers]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 5 - Surface Controllers]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 5 - Surface Controllers]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 5 - Surface Controllers]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 5 - Surface Controllers]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 5 - Surface Controllers]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 5 - Surface Controllers]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 5 - Surface Controllers]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 5 - Surface Controllers]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 5 - Surface Controllers]]> <![CDATA[Umbraco v5 Surface Controller Forms Umbraco v5 Surface Controller Forms]]>
<![CDATA[Sharing Controller Actions with ControllerExtenders]]> Why?

If you wanted to be able to share Actions between controllers in .Net there is currently no official way to do it and that is probably because it might not be something that people have thought about doing very often before. Though once I started thinking about it I realized that this concept could be used for a variety of different purposes and that other people might potentially think of whole new ways to apply this concept. Here’s a couple use cases:

  • Separating logic out of large controllers
  • Ability to distribute Controllers in DLLs whose Actions that could then be consumed by other people’s Controllers
  • Support for a ‘Multiple inheritance’ class structure

Again I think that there is some potential here for people to run with this concept in their own ways. Its probably not a concept that everyone will want/need to use, but you should know that it definitely can be done, and here’s how…

ControllerExtender

In order to extend your Controller with actions from another Controller, you’ll need to register your extension with a new class called ControllerExtender. There’s a couple of ways to go about doing this, the nicest way is to use attributes on your Controller:

[ExtendedBy(typeof(TestExtenderController))]
public class ContentEditorController : Controller
{....}

Otherwise there’s a few overloads on the ControllerExtender class to directly do this:

//Where 'this' is the controller you are extending, generally called in the 
//constructor of your controller
ControllerExtender.RegisterExtender(this, typeof (TestExtenderController));

//Where 'this' is the controller you are extending, generally called in the 
//constructor of your controller
ControllerExtender.RegisterExtender<TestExtenderController>(this);

//This registration could be created in your global.asax 
ControllerExtender.RegisterExtender<ContentEditorController, TestExtenderController>();

One important thing to note is that the ControllerExtender uses the DependencyResolver to create an instance of the extending controller class so you’ll need to ensure that your controllers are registered properly in IoC.

Illegal Extenders

The ControllerExtender will not let you extend a controller by it’s same type of it’s same sub type. Also, nested extenders do not work (though the code could be modified to support this) therefore you cannot have Controller ‘A’ be extended by Controller ‘B’ which is extended by Controller ‘C’. In this scenario when rendering actions on Controller ‘A’, only actions on Controller ‘A’ and ‘B’ will be resolved. When rendering actions on Controller ‘B’ only actions on Controller ‘B’ and ‘C’ will be resolved.

Multiple Extenders

You can register multiple extenders for one Controller but because multiple extenders may have the same Action name/signature, only the first one that is found that is a match is used. It is therefor up to the developer to make sure they are aware of this.

Custom IActionInvoker

In order to facilitate the sharing of Actions a custom IActionInvoker of type ControllerExtenderActionInvoker needs to be registered on your controller. This is easy to do in the constructor of your controller:

public MyController()
{
    this.ActionInvoker = new ControllerExtenderActionInvoker();
}

Source Code

The source code for all of this is pretty straight forward and boils down to 3 classes:

  • The static ControllerExtender class
  • The custom ControllerExtenderActionInvoker
  • The ExtendedByAttribute

ControllerExtenderActionInvoker class

This class is responsible for finding and invoking the correct Action on a controller which takes into account any of the extenders registered for the currently executing Controller.

The most up to date code can be found in the Umbraco 5 source code HERE.

ControllerExtender class

This class is responsible for maintaining the extender registrations, it allows for creating registrations and returning registrations:

public static class ControllerExtender
{

    /// <summary>
    /// Internal ConcurrentDictionary to store all registrations
    /// </summary>
    private static readonly ConcurrentDictionary<Tuple<Type, Type>, Func<ControllerBase>> 
        Registrations
            = new ConcurrentDictionary<Tuple<Type, Type>, Func<ControllerBase>>();

    /// <summary>
    /// Registers the extender.
    /// </summary>
    /// <typeparam name="TController">The type of the controller.</typeparam>
    /// <typeparam name="TExtender">The type of the extender.</typeparam>
    public static void RegisterExtender<TController, TExtender>()
        where TController : ControllerBase
        where TExtender : ControllerBase
    {
        var t = new Tuple<Type, Type>(typeof(TController), typeof(TExtender));
        if (Registrations.ContainsKey(t))
            return;

        if (typeof(TExtender).IsAssignableFrom(typeof(TController)))
        {
            throw new InvalidOperationException
                ("Cannot extend a controller by it's same type");
        }

        Registrations.TryAdd(t, () => DependencyResolver.Current.GetService<TExtender>());
    }

    /// <summary>
    /// Registers the extender.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="controllerToExtend">The controller to extend.</param>
    public static void RegisterExtender<T>(
        ControllerBase controllerToExtend)
        where T : ControllerBase
    {
        RegisterExtender(controllerToExtend, () => DependencyResolver.Current.GetService<T>());
    }

    /// <summary>
    /// Registers the extender.
    /// </summary>
    /// <param name="controllerToExtend">The controller to extend.</param>
    /// <param name="controllerExtender">The controller extender.</param>
    public static void RegisterExtender(
        ControllerBase controllerToExtend, 
        Type controllerExtender)
    {
        var t = new Tuple<Type, Type>(controllerToExtend.GetType(), controllerExtender);
        if (Registrations.ContainsKey(t))
            return;

        if (controllerExtender.IsAssignableFrom(controllerToExtend.GetType()))
        {
            throw new InvalidOperationException
                ("Cannot extend a controller by it's same type");
        }

        Registrations.TryAdd(t, 
            () => DependencyResolver.Current.GetService(controllerExtender) as ControllerBase);
    }

    /// <summary>
    /// Registers the extender.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="controllerToExtend">The controller to extend.</param>
    /// <param name="extender">The extender.</param>
    public static void RegisterExtender<T>(
        ControllerBase controllerToExtend, 
        Expression<Func<T>> extender)
        where T : ControllerBase
    {
        var extenderType = typeof(T);
        var t = new Tuple<Type, Type>(controllerToExtend.GetType(), extenderType);
        if (Registrations.ContainsKey(t))
            return;

        if (extender.GetType().IsAssignableFrom(controllerToExtend.GetType()))
        {
            throw new InvalidOperationException
                ("Cannot extend a controller by it's same type");
        }

        Registrations.TryAdd(t, extender.Compile());
    }

    /// <summary>
    /// Returns all registrations as a readonly collection
    /// </summary>
    /// <returns></returns>
    public static IEnumerable<KeyValuePair<Tuple<Type, Type>, Func<ControllerBase>>> 
        GetRegistrations()
    {
        return Registrations;
    }

}

ExtendedByAttribute class

This Attribute is used by the ControllerExtenderActionInvoker to created Extender registrations dynamically.

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ExtendedByAttribute : Attribute
{
    public Type ControllerExtenderType { get; private set; }

    public ExtendedByAttribute(Type controllerExtenderType)
    {
        if (!typeof(ControllerBase).IsAssignableFrom(controllerExtenderType))
        {
            throw new ArgumentException
                ("controllerExtenderType must be of type Controller");
        }
        ControllerExtenderType = controllerExtenderType;       
    }
}
]]>
<![CDATA[Umbraco Jupiter Plugins - Part 4 - Editors]]> 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.

]]>
<![CDATA[re: Umbraco Jupiter Plugins - Part 4 - Editors]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 4 - Editors]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 4 - Editors]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 4 - Editors]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 4 - Editors]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 4 - Editors]]> <![CDATA[Umbraco Jupiter Plugins - Part 5 - Surface Controllers Umbraco Jupiter Plugins - Part 5 - Surface Controllers]]> <![CDATA[Pingback from h4rdboiledegg.wordpress.com Adventures with Umbraco 5 Part 3 – The Editor « h4rdboiledegg]]>
<![CDATA[Umbraco Jupiter Plugins - Part 3 - Trees]]> This is the third 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 a tree. A more in-depth example including rendering out child nodes, using many of the inbuilt helper/extension methods will come in a future blog, though in the meantime once you’ve read this post if you want to see more in-depth examples you can easily find them in our v5 source code.

Related Posts:

  1. Umbraco Jupiter Plugins – Part 1
  2. Umbraco Jupiter Plugins – Part 2 - Routing

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 a tree

A tree in Umbraco v5 is actually an MVC Controller that returns JSON data. The first step to creating a tree is to create a class for your tree that inherits from the Umbraco base tree controller class: Umbraco.Cms.Web.Trees.TreeController

Important convention: All Tree controller names MUST be suffixed with ‘TreeController’. For example, if you are creating a tree to display system information, you might call your Tree: SystemInfoTreeController. If you don’t follow this convention, your tree controller won’t be routed.

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

[Tree("A18108B1-9C86-4B47-AC04-A3089FE8D3EA", "My Custom Tree")]

The two parameters passed to this attribute are:

  • The tree plugin ID (this MUST be unique so ensure you generated a new GUID for every single one of your plugins)
  • The tree title. This will be the text rendered for the root node of your tree, however, this can be overridden and you could render out any title that you wish for your root node and it could even be dynamic. Also note that we will be supporting localization for the tree title.

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

//mark assembly for export as a tree plugin
[assembly: TreePluginAssembly]
[assembly: AssemblyContainsPlugins]

Creating a tree

Constructor

When inheriting from the base Umbraco.Cms.Web.Trees.TreeController, you will be required to create a constructor accepting an parameter of type: IBackOfficeRequestContext :

[Tree("A18108B1-9C86-4B47-AC04-A3089FE8D3EA", "My Custom Tree")]
public class MyTreeController : TreeController
{
    public MyTreeController(IBackOfficeRequestContext requestContext)
        : base(requestContext)
    {
    }

    //more code will go here....
    
}

The IBackOfficeRequestContext will most likely contain references to everything you’ll need to get the data for your tree. It includes references to:

  • Hive
  • Umbraco settings
  • The TextManager (localization framework)
  • All of the registered plugins in the system
  • … and a whole lot more

However, you’ll be please to know that all plugins including Trees can take part in IoC contructor injection. So, if you want more objects injected into your tree controller you can just add the parameters to your constructor and they’ll be injected so long as they exist in the IoC container.

Overriding methods/properties

There is one property and one method you need to override:

RootNodeId

This property is just a getter and returns the root node id for your tree. Many trees exist at the absolute root of the data which is called the SystemRoot. An example of a tree that exists at the system root would be trees like the: Data Type tree, Macro tree, Packages tree, tc… since they don’t have a heirarchy. Tree’s that have different start node Ids are trees like: Content, Media and Users.  Since each one of those entities share the same data structure, we separate these data structures under different start nodes from the SystemRoot.

For the most part, if you are creating a utility type tree or a custom tree that doesn’t exist under a special hierarchy, the SystemRoot is what you’ll want:

protected override HiveEntityUri RootNodeId
{
    get { return FixedHiveIds.SystemRoot; }
}

GetTreeData

This method is the method that returns the JSON tree data though to make it easy you don’t have to worry about JSON whatsoever. All you need to do is add TreeNode objects to the existing NodeCollection of the tree controller.

As a very simple example, if you wanted to render out one node in your tree you could do this:

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

The CreateTreeNode is a helper method which is part of the base TreeController class that has many useful overloads. In this example, we’re giving it an id, not passing in any custom query string parameters, a title, not giving it an editor url and tagging the node as not having any children.

Registering a tree

In order to get your tree to show up in the back office, you need to register the tree in the config file: ~/App_Data/Umbraco/Config/umbraco.cms.trees.config , and here’s all you need to do to put it in the ‘settings’ app (as an example):

<add application="settings" 
     controllerType="MyProject.MyTreeController, MyProject" />

NOTE: At CodeGarden we discussed that you can ship your plugin inside a package and have your own config file deployed which Umbraco will recognize so that you don’t have to edit the already existing file…. This is still true! But we’ll write another blog post about that Smile

More in depth example?

As I mentioned at the start of this post I’ll write another one detailing our many extension and helper methods when rendering out trees, how to add menu items to your nodes, customize your icons, change the editor for particular nodes, etc… In the meantime though, please have a look at the v5 source code, the trees all exist in the project: Umbraco.Cms.Web.Trees

]]>
<![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 3 - Trees]]> <![CDATA[Umbraco Jupiter Plugins - Part 4 - Editors Umbraco Jupiter Plugins - Part 4 - Editors]]>
<![CDATA[Partial View macros in Umbraco v5]]> 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.

Macro Types

In Umbraco v5, there are currently 3 types of Macros:

  • Xslt
  • Partial View
  • Surface Action

The Xslt macro will remain very similar to the v4 Xslt macro, but the 2 other types are brand new. This post will cover the new Partial View Macro.

A Partial View in MVC is sort of synonymous with a User Control in WebForms. Its simply just a Razor view as a cshtml file. If you like Umbraco v4’s Razor macros, then you’ll be pleased to know that Razor is absolutely native to v5 and the Partial View Macro will be one of your best tools for working with v5.

Creating a Partial View macro

The first thing you’ll have to do is create the partial view, which you will need to save in the ~/Views/Umbraco/Partial folder. Next, a partial view macro needs to inherit from a custom view type, so the declaration at the top of your view will need to be:

@inherits PartialViewMacro

Then, just like in v4, you’ll need to create a new macro in the Developer section of the Umbraco back office. The Macro Property interface looks very similar in v5:

image

You’ll notice its slightly simplified as compared to v4. The 2nd drop down list dynamically changes based on the Macro Type drop down list value.

Once you’ve saved the macro, that’s it, your Macro is now created!

Using a Partial View macro

The razor syntax for rendering a macro in v5 is:

@Html.UmbracoMacro("blah")

As noted before, a Partial View Macro inherits from the view type: PartialViewMacro . This view object contains a Model property of type: Umbraco.Cms.Model.PartialViewMacroModel which has a couple of properties you can use to render data to the page:

public Content CurrentNode { get; }
public dynamic MacroParameters { get; }

The CurrentNode property is very similar to v4’s currentPage parameter in Xslt. It will allow you to traverse the tree and render any content you like. Here’s one way that you could list the child names from the current node:

<h2>Names of child nodes</h2>
@foreach (var child in Model.CurrentNode.ChildContent().AsDynamic())
{
    <p>
        Child node name: <b>@child.Name</b>
    </p>
}

Dynamic parameters

As you can see above, there’s a MacroParameters property on the PartialViewMacroModel which is a dynamic property just like MVC’s ViewBag. Passing data into the MacroParameters property can be done in your Macro declaration like so:

@Html.UmbracoMacro("blah", new { IsCool = true, MyParameterName = new MyObject() })

This means that you can pass any type of object that you’d like into your macro with any parameter name. Then to use the parameters that you’ve passed in, you can reference them directly by name inside your macro:

<ul>
    <li>@Model.MacroParameters.IsCool</li>
    <li>@Model.MacroParameters.MyParameterName.ToString()</li>
</ul>

Macro parameters via the Macro Editor

A cool new feature in v5 is the new Macro parameter editor. It can now pre-populate all macro parameters found in Xslt, Partial Views and Surface controllers. Better still, is that the parameter editor has been completely rebuilt with Knockout JS so you can add/remove as many parameters as you like at once and then finally post your changes back when hitting save.

image

Oh, and another great feature in v5 is that the editors for macro parameters are actually just v5 Property Editors that are attributed as Macro Parameter Editors.

Strongly typed parameters

You may be wondering how the Macro Editor populates parameters from a Partial View Macro since we’ve seen that Partial View Macro model only supports dynamic (non stongly typed) properties… The answer is in Razor. Razor views allow you to define public properties, methods, etc… inside of the Razor markup. So if we want to have strongly typed parameters for our Partial View Macros which can be set based on Macro parameters in the rich text editor, all we have to do is declare them like:

@inherits PartialViewMacro

@functions {

    public bool IsCool { get; set; }
    
}

Now, the Partial View has a discoverable property which our Macro Editor will be able to see and automatically populate the parameter list. This property will also be set with any value that is selected in the Macro Parameter Editor when inserting one into the rich text box. Another thing to note is that if you are simply injecting parameter values using the Html.Macro helper, then this property will be set so long as a dynamic property of the same name exists in the macro’s MacroParameter model properties.

]]>
<![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[re: Partial View macros in Umbraco v5]]> <![CDATA[Umbraco v5 Surface Controller Forms Umbraco v5 Surface Controller Forms]]>
<![CDATA[Sharing views between specific controllers]]> There’s no native way in MVC to share views between controllers without having to put those views in the ‘Shared’ folder which can be annoying especially if you have an inherited controller class structure, or your simply wish to just have one particular controller look for views in the folder of a different controller.

With a little help from DotPeek to see what’s going on inside of the VirtualPathProviderViewEngine, I’ve created a fairly elegant solution to the above problem which consists of a custom ViewEngine and a custom controller Attribute. Lets start with the custom Attribute, its really simple and only contains one property which is the name of the controller that you wish the attributed controller to reference views.  An example:

[AlternateViewEnginePath("ContentEditor")]
public class MediaEditorController : Controller
{  ...  }

The example above is saying that we have a MediaEditor controller that should reference views in the ContentEditor controller’s view folder, pretty simple right! A cool part about how the underlying ViewEngine works is that if a view isn’t found in the ContentEditor controller’s folder, then it will check back to the current controller’s folder, so it has built in fall back support.

The custom ViewEngine is actually pretty simple as well once you know what’s going on inside of the VirtualPathProviderViewEngine. There’s two particular methods: FindView and FindPartialView which the VirtualPathProviderViewEngine figures out which controller/folder to look in. It figures this out by looking at the current ControllerContext’s RouteValues and simply does a lookup of the controller name by using this statement:

controllerContext.RouteData.GetRequiredString("controller");

So all we’ve got to do is override the FindView and FindPartialView methods, create a custom ControllerContext with the “controller” route value to be the value specified in our custom attribute, and then pass this custom ControllerContext into the underlying base FindView/FindPartial view methods:

/// <summary>
/// A ViewEngine that allows a controller's views to be shared with other 
/// controllers without having to put these shared views in the 'Shared' folder.
/// This is useful for when you have inherited controllers.
/// </summary>
public class AlternateLocationViewEngine : RazorViewEngine
{
    public override ViewEngineResult FindPartialView(
        ControllerContext controllerContext, 
        string partialViewName, 
        bool useCache)
    {
        var altContext = GetAlternateControllerContext(controllerContext);
        if (altContext != null)
        {
            //see if we can get the view with the alternate controller 
            //specified, if its found return the result, if its not found
            //then return the normal results which will try to find 
            //the view based on the 'real' controllers name.
            var result = base.FindPartialView(altContext, partialViewName,useCache);
            if (result.View != null)
            {
                return result;
            }
        }
        return base.FindPartialView(controllerContext, partialViewName,useCache);
    }

    public override ViewEngineResult FindView(
        ControllerContext controllerContext, 
        string viewName, 
        string masterName, 
        bool useCache)
    {
        var altContext = GetAlternateControllerContext(controllerContext);
        if (altContext!= null)
        {
            var result = base.FindView(altContext, viewName, masterName, useCache);
            if (result.View != null)
            {
                return result;
            }
        }
        return base.FindView(controllerContext, viewName, masterName, useCache);
    }

    /// <summary>
    /// Returns a new controller context with the alternate controller name in the route values
    /// if the current controller is found to contain an AlternateViewEnginePathAttribute.
    /// </summary>
    /// <param name="currentContext"></param>
    /// <returns></returns>
    private static ControllerContext GetAlternateControllerContext(
        ControllerContext currentContext)
    {
        var controller = currentContext.Controller;
        var altControllerAttribute = controller.GetType()
            .GetCustomAttributes(typeof(AlternateViewEnginePathAttribute), false)
            .OfType<AlternateViewEnginePathAttribute>()
            .ToList();
        if (altControllerAttribute.Any())
        {
            var altController = altControllerAttribute.Single().AlternateControllerName;
            //we're basically cloning the original route data here...
            var newRouteData = new RouteData
                {
                    Route = currentContext.RouteData.Route,
                    RouteHandler = currentContext.RouteData.RouteHandler
                };
            currentContext.RouteData.DataTokens
                .ForEach(x => newRouteData.DataTokens.Add(x.Key, x.Value));
            currentContext.RouteData.Values
                .ForEach(x => newRouteData.Values.Add(x.Key, x.Value));

            //now, update the new route data with the new alternate controller name
            newRouteData.Values["controller"] = altController;

            //now create a new controller context to pass to the view engine
            var newContext = new ControllerContext(
                currentContext.HttpContext, 
                newRouteData, 
                currentContext.Controller);
            return newContext;
        }

        return null;
    }
}

/// <summary>
/// An attribute for a controller that specifies that the ViewEngine 
/// should look for views for this controller using a different controllers name.
/// This is useful if you want to share views between specific controllers 
/// but don't want to have to put all of the views into the Shared folder.
/// </summary>
public class AlternateViewEnginePathAttribute : Attribute
{
    public string AlternateControllerName { get; set; }

    public AlternateViewEnginePathAttribute(string altControllerName)
    {
        AlternateControllerName = altControllerName;
    }
}
Lastly, you’ll need to just register this additional ViewEngine in your global.asax, or IoC, or however you are doing that sort of thing in your application.]]>
<![CDATA[re: Sharing views between specific controllers]]> <![CDATA[re: Sharing views between specific controllers]]>
<![CDATA[Umbraco Jupiter Plugins - Part 2 - Routing]]> 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 :)

]]>
<![CDATA[re: Umbraco Jupiter Plugins - Part 2 - Routing]]> <![CDATA[Umbraco Jupiter Plugins - Part 3 - Trees Umbraco Jupiter Plugins - Part 3 - Trees]]>
<![CDATA[Umbraco Jupiter Plugins - Part 1]]> This is the first blog post in a series of posts relating to building plugins for Umbraco v5 (Jupiter)

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.

What is a plugin

Since Umbraco Jupiter has been built from the ground up, we first need to define some v5 terminology:

  • Plugin = A single functional component that extends Umbraco such as a Tree, an Editor, a Menu Item, etc…
  • Package = A group of Plugins installed into Umbraco via the ~/Plugins/Packages/[Package Name] folder

The Umbraco v5 back-office has been architected to run entirely on Plugins, in fact the core trees, editors, etc… that are shipped with Umbraco are Plugins in v5.

Types of plugins

The list of Plugin types will most likely increase from the time of this blog post to when Jupiter is launched but as it stands now here are the types of Plugins supported in v5:

  • Property Editors
    • This term is new to v5. In v4.x there was no differentiation between a Data Type and it’s underlying ‘Data Type’ editor. In v5 we’ve made a clear distinction between a ‘Data Type’ (as seen in the Data Type tree and used as properties for Document Types) and the underlying editor and pre-value editor that it exposes.  An example of a Property Editor would be uComponents’ Multi-Node Tree Picker. An example of a Data Type would be when an Umbraco administrator creates a new Data Type node in the Data Type tree and assigns the Multi-Node Tree Picker as it’s Property Editor.
    • So uComponents Team, this is where you need to focus your efforts for version 5!
  • Menu Items
    • Context menu items such as Create, Publish, Audit Trail, etc… are all plugins.
    • See this post in regards to creating menu items in v5, though there have been some new features added since that article was created which I’ll detail in coming posts in this series.
  • Editors
    • Editor plugins are all of the interactions performed in the right hand editor panel and in modal dialogs in the back-office.
    • For example, the Content Editor core plugin in v5 manages the rendering for all views such as editing content, sorting, copying, and moving nodes, and nearly all of the other views that the context menu actions render.
    • Editors are comprised mostly of MVC Controllers, Views, JavaScript & CSS.
  • Trees
    • All trees are plugins, for example, the Content tree, Media tree, Document Type tree are all different plugins.
    • Trees are actually MVC controllers.
    • Tree nodes use Menu Items to render Editors
  •  Presentation Addins (Yet to be officially named)
    • Another type of plugin are Controllers that are installed via packages that interact with the presentation layer, an example of this might be the Controller Action that accepts the post values from a Contour form.

Whats next?

In the coming blog posts I’ll talk about

  • how plugins are installed and loaded
  • how the Umbraco routing system works with all of these controllers
  • 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 :)

]]>
<![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[re: Umbraco Jupiter Plugins - Part 1]]> <![CDATA[Umbraco Jupiter Plugins - Part 2 - Routing Umbraco Jupiter Plugins - Part 2 - Routing]]> <![CDATA[Partial View macros in Umbraco v5 Partial View macros in Umbraco v5]]> <![CDATA[Pingback from nishantwork.wordpress.com Useful Resources for Umbraco CMS development « Nishant works @ Umbraco]]>
<![CDATA[Ultra fast media performance in Umbraco]]> There’s a few different ways to query Umbraco for media: using the new Media(int) API , using the umbraco.library.GetMedia(int, false) API or querying for media with Examine. I suppose there’s quite a few people out there that don’t use Examine yet and therefore don’t know that all of the media information is actually stored there too! The problem with the first 2 methods listed above is that they make database queries, the 2nd method is slightly better because it has built in caching, but the Examine method is by far the fastest and most efficient.

The following table shows you the different caveats that each option has:

new Media(int)

library.GetMedia(int,false)

Examine

Makes DB calls

yes

yes

no

Caches result

no

yes

no

Real time data

yes

yes

no

You might note that Examine doesn’t cache the result whereas the GetMedia call does, but don’t let this fool you because the Examine searcher that returns the result will be nearly as fast as ‘In cache’ data but won’t require the additional memory that the GetMedia cache does. The other thing to note is that Examine doesn’t have real time data. This means that if an administrator creates/saves a new media item it won’t show up in the Examine index instantaneously, instead it may take up to a minute to be ingested into the index. Lastly, its obvious that the new Media(int) API isn’t a very good way of accessing Umbraco media because it makes a few database calls per media item and also doesn’t cache the result.

Examine would be the ideal way to access your media if it was real time, so instead, we’ll combine the efforts of Examine and library.GetMedia(int,false) APIs. First will check if Examine has the data, and if not, revert to the GetMedia API. This method will do this for us and return a new object called MediaValues which simply contains a Name and Values property:

First here’s the usage of the new API below:

var media = MediaHelper.GetUmbracoMedia(1234); var mediaFile = media["umbracoFile"];

That’s a pretty easy way to access media. Now, here’s the code to make it work:

public static MediaValues GetUmbracoMedia(int id) { //first check in Examine as this is WAY faster var criteria = ExamineManager.Instance .SearchProviderCollection["InternalSearcher"] .CreateSearchCriteria("media"); var filter = criteria.Id(id); var results = ExamineManager .Instance.SearchProviderCollection["InternalSearcher"] .Search(filter.Compile()); if (results.Any()) { return new MediaValues(results.First()); } var media = umbraco.library.GetMedia(id, false); if (media != null && media.Current != null) { media.MoveNext(); return new MediaValues(media.Current); } return null; }

 

The MediaValues class definition:

public class MediaValues { public MediaValues(XPathNavigator xpath) { if (xpath == null) throw new ArgumentNullException("xpath"); Name = xpath.GetAttribute("nodeName", ""); Values = new Dictionary<string, string>(); var result = xpath.SelectChildren(XPathNodeType.Element); while(result.MoveNext()) { if (result.Current != null && !result.Current.HasAttributes) { Values.Add(result.Current.Name, result.Current.Value); } } } public MediaValues(SearchResult result) { if (result == null) throw new ArgumentNullException("result"); Name = result.Fields["nodeName"]; Values = result.Fields; } public string Name { get; private set; } public IDictionary<string, string> Values { get; private set; } }

That’s it! Now you have the benefits of Examine’s ultra fast data access and real-time data in case it hasn’t made it into Examine’s index yet.

]]>
<![CDATA[re: Ultra fast media performance in Umbraco]]> <![CDATA[re: Ultra fast media performance in Umbraco]]> <![CDATA[re: Ultra fast media performance in Umbraco]]> <![CDATA[re: Ultra fast media performance in Umbraco]]> <![CDATA[re: Ultra fast media performance in Umbraco]]> <![CDATA[re: Ultra fast media performance in Umbraco]]> <![CDATA[re: Ultra fast media performance in Umbraco]]> <![CDATA[re: Ultra fast media performance in Umbraco]]> <![CDATA[re: Ultra fast media performance in Umbraco]]>
<![CDATA[HtmlHelper Table methods]]> I was hoping that these were built already but couldn’t see any descent results with a quick Google search so figured I’d just write my own… these are now part of the Umbraco v5 codebase. Here’s 2 HtmlHelper methods that allow you to very quickly create an Html table output based on an IEnumerable data structure. Luckily for us, Phil Haack showed us what Templated Razor Delegates are which makes stuff like this very elegant.

There are 2 types of tables: a table that expands vertically (you set a maximum number of columns), or a table that expands horizontally (you set a maximum amount of rows). So I’ve created 2 HtmlHelper extensions for this:

Html.TableHorizontal Html.TableVertical

Say you have a partial view with a declaration of something like:

@model IEnumerable<MyDataObject>

To render a table is just one call and you can customize exactly how each cell is rendered and styled using Razor delegates, in the following example the MyDataObject class contains 3 properties: Name, Enabled and Icon and each cell is going to render a check box with a CSS image as it’s label and there will be a maximum of 8 columns:

@Html.TableVertical(Model, 8, @<text> @Html.CheckBox(@item.Name, @item.Enabled) <label for="@Html.Id(@item.Name)" class="@item.Icon"> <span>@item.Name</span> </label> </text>)

Nice! that’s it, far too easy. One thing to note is the @<text> </text> syntax as this is special Razor parser syntax that declares a Razor delegate without having to render additional html structures. Generally Razor delegates will require some Html tags such as this: @<div> </div> but if you don’t require surrounding Html structures, you can use the special @<text> </text> tags.

Lastly here’s all the HtmlHelper code… I’ve created these extensions as HtmlHelper extensions only for consistency but as you’ll be able to see, the HtmlHelper is never actually used and these extensions could simply be extensions of IEnumerable<T>.

/// <summary> /// Creates an Html table based on the collection /// which has a maximum numer of rows (expands horizontally) /// </summary> public static HelperResult TableHorizontal<T>(this HtmlHelper html, IEnumerable<T> collection, int maxRows, Func<T, HelperResult> template) where T : class { return new HelperResult(writer => { var items = collection.ToArray(); var itemCount = items.Count(); var maxCols = Convert.ToInt32(Math.Ceiling(items.Count() / Convert.ToDecimal(maxRows))); //construct a grid first var grid = new T[maxCols, maxRows]; var current = 0; for (var x = 0; x < maxCols; x++) for (var y = 0; y < maxRows; y++) if (current < itemCount) grid[x, y] = items[current++]; WriteTable(grid, writer, maxRows, maxCols, template); }); } /// <summary> /// Creates an Html table based on the collection /// which has a maximum number of cols (expands vertically) /// </summary> public static HelperResult TableVertical<T>(this HtmlHelper html, IEnumerable<T> collection, int maxCols, Func<T, HelperResult> template) where T : class { return new HelperResult(writer => { var items = collection.ToArray(); var itemCount = items.Count(); var maxRows = Convert.ToInt32(Math.Ceiling(items.Count() / Convert.ToDecimal(maxCols))); //construct a grid first var grid = new T[maxCols, maxRows]; var current = 0; for (var y = 0; y < maxRows; y++) for (var x = 0; x < maxCols; x++) if (current < itemCount) grid[x, y] = items[current++]; WriteTable(grid, writer, maxRows, maxCols, template); }); } /// <summary> /// Writes the table markup to the writer based on the item /// input and the pre-determined grid of items /// </summary> private static void WriteTable<T>(T[,] grid, TextWriter writer, int maxRows, int maxCols, Func<T, HelperResult> template) where T : class { //create a table based on the grid writer.Write("<table>"); for (var y = 0; y < maxRows; y++) { writer.Write("<tr>"); for (var x = 0; x < maxCols; x++) { writer.Write("<td>"); var item = grid[x, y]; if (item != null) { //if there's an item at that grid location, call its template template(item).WriteTo(writer); } writer.Write("</td>"); } writer.Write("</tr>"); } writer.Write("</table>"); }
]]>
<![CDATA[re: HtmlHelper Table methods]]> <![CDATA[re: HtmlHelper Table methods]]>
<![CDATA[Searching Umbraco using Razor and Examine]]> This post was imported from FARMCode.org which has been discontinued. These posts now exist here as an archive. They may contain broken links and images.Since Razor is really just c# it’s super simple to run a search in Umbraco using Razor and Examine.  In MVC the actual searching should be left up to the controller to give the search results to your view, but in Umbraco 4.6 + , Razor is used as macros which actually ‘do stuff’. Here’s how incredibly simple it is to do a search:
@using Examine; @* Get the search term from query string *@ @{var searchTerm = Request.QueryString["search"];} <ul class="search-results"> @foreach (var result in ExamineManager.Instance.Search(searchTerm, true)) { <li> <span>@result.Score</span> <a href="@umbraco.library.NiceUrl(result.Id)"> @result.Fields["nodeName"] </a> </li> } </ul>

That’s it! Pretty darn easy.

And for all you sceptics who think there’s too much configuration involved to setup Examine, configuring Examine requires 3 lines of code. Yes its true, 3 lines, that’s it. Here’s the bare minimum setup:

1. Create an indexer under the ExamineIndexProviders section:

<add name="MyIndexer" type="UmbracoExamine.UmbracoContentIndexer, UmbracoExamine"/>

2. Create a searcher under the ExamineSearchProviders section:

<add name="MySearcher" type="UmbracoExamine.UmbracoExamineSearcher, UmbracoExamine"/>

3. Create an index set under the ExamineLuceneIndexSets config section:

<IndexSet SetName="MyIndexSet" IndexPath="~/App_Data/TEMP/MyIndex" />

This will index all of your data in Umbraco and allow you to search against all of it. If you want to search on specific subsets, you can use the FluentAPI to search and of course if you want to modify your index, there’s much more you can do with the config if you like.

With Examine the sky is the limit, you can have an incredibly simple index and search mechanism up to an incredibly complex index with event handlers, etc… and a very complex search with fuzzy logic, proximity searches, etc…  And no matter what flavour you choose it is guaranteed to be VERY fast and doesn’t matter how much data you’re searching against.

I also STRONGLY advise you to use the latest release on CodePlex: http://examine.codeplex.com/releases/view/50781 . There will also be version 1.1 coming out very soon.

Enjoy!

]]>
<![CDATA[re: Searching Umbraco using Razor and Examine]]> <![CDATA[re: Searching Umbraco using Razor and Examine]]> <![CDATA[re: Searching Umbraco using Razor and Examine]]> <![CDATA[re: Searching Umbraco using Razor and Examine]]> <![CDATA[re: Searching Umbraco using Razor and Examine]]> <![CDATA[Pingback from joeriks.wordpress.com Ajax-enabled search in Umbraco (using Examine and Razor) « Not everything is codeable]]>
<![CDATA[Auto Sort package for Umbraco released]]> This post was imported from FARMCode.org which has been discontinued. These posts now exist here as an archive. They may contain broken links and images.After sorting 150 nodes manually in the Umbraco backend I thought to myself that it can’t be too hard to write some kind of automatic sorting dialog. First I thought about adding some options to the existing sort dialog, which would swirl the child nodes in the list around to the editors content, yet that seemed like too much effort to just sort the nodes, the editor would still have the option to do some manual ordering using the built-in Umbraco sort after the automatic sort. The next idea was to add another option to the context menu, then ideally open up a sub menu so you could just go ‘Auto sort –> descending’ and it would go off. Apart from the fact that it would be quite a bit of work to get that sub menu working (I recently read somewhere that it’s probably coming in version 5 Smile, looking forward already) it had a couple of additional downfalls: the sort might be triggered by accident and it would be quite difficult to get additional options in there, e.g. the field you want to sort by. That pretty much left the option to give Auto Sort it’s very own popup window.

The options I ended up with in the end are the following:

  • The field to sort the nodes by. Currently supported are
    • node name
    • id
    • creation date
    • note type alias and
    • custom fields (you have to provide the alias of your custom property);
    additionally for content nodes there are also
    • update date
    • release date
    • expiry date and
    • creator name
    to choose from. (default: node name)
  • Sort either ascending or descending (default: ascending)
  • Include grand children in the sort or not. Including grand children will sort ALL children and grand children by the field you have selected recursively. (default: exclude grand children)
  • Include all unpublished nodes in the sort, or choose to exclude them. (default: include)
  • If you exclude unpublished nodes from the sort you will need to provide the location of the unpublished nodes, either at the top of the list or at the bottom (default: top)

Once the first sort using node name was working it was a nearly a breeze to make the additional options work as well. Some issues occurred with regards to the differences between content and media nodes, but nothing that a couple of if-else statements couldn’t handle. Here are some screen shots:

 

 

The trickier bit was then to add support for multiple languages. The respective keys had to be added to the specific language xml files in /umbraco/config/lang. The Package Actions Contrib package by Richard Soeteman (essential for each Umbraco package builder) contains the fantastic AddLanguageFileKey action by Chris Houston, which would have done the deed yet would also have been a bit cumbersome since I had to add like 20 keys for each language, and also I wanted to add my own area in the language files. So I extended the custom package action to take a list of key-value-pairs and the name for a new are to create the section in the specified language file [note to self: send the code to Richard Soeteman so he can add it to the contrib package]. At the time of writing there are only 2 languages missing thanks to the community, which is absolutely awesome, I’ll include them shortly in the package. Credit goes to the following translators:

  • kows for the Dutch version
  • Patrik Wibron for the Swedish version
  • Mike for the French version
  • Morten Balle for the Dansk version
  • ricardo for Italiano and Spanish (double high five!)
  • Korean version anyone?
  • Norwegian maybe?

I hope you enjoy the package and that it makes your life even easier than developing web sites with Umbraco already is. Skål!

]]>
<![CDATA[re: Auto Sort package for Umbraco released]]>
<![CDATA[Using metadata with MEF in Medium Trust]]> One of the awesome parts of MEF is that you can attach metadata to your objects. This allows you to use the new Lazy<T, TMetadata> object so you can inspect the meta data about an object without instantiating it. In order to attach metadata to an object, you need (should have) some entity that contains properties to support the meta data such as an interface (good tutorial site here ). For example, if you have a class of type MyObjectType and an interface to store metadata about the class of type IMyMetadata, you can then resolve/import Lazy<MyObjectType, IMyMetadata> which will expose a Metadata property of type IMyMetadata with the information filled in. You might already be able to tell that a bit of magic is happening behind the scenes since there is no concrete class for IMyMetadata but MEF has magically found a way to instantiate a class of type IMyMetadata and fill in the values. This is the problem area if you are running in Medium Trust, you will get a SecurityException stemming form the System.ComponentModel.Composition.MetadataViewGenerator. This same issue will occur when using Autofac to register metadata with the .WithMetadata extension method.

Solution

To work around this problem in Medium Trust, you’ll need to create a concrete class to store your metadata in instead of just referencing an interface. You’ll also need to ensure that the constructor of this class takes in one parameter of type IDictionary<string, object> and using this object you’ll need to manually do the heavy lifting of assigning the values to the properties of this class based on the values in the dictionary. Better yet, you can just make a base class that all your metadata classes can inherit from. In Umbraco v5, we’ve called this abstract class MetadataComposition just to keep inline with the naming conventions of the MEF namespace:

public abstract class MetadataComposition { /// <summary> /// constructor, sets all properties of this object based /// on the dictionary values /// </summary> /// <param name="obj"></param> protected MetadataComposition(IDictionary<string, object> obj) { var t = GetType(); var props = t.GetProperties(); foreach (var a in obj) { var p = props.Where(x => x.Name == a.Key).SingleOrDefault(); if (p != null) { p.SetValue(this, a.Value, null); } } } }

Hope this helps someone!

]]>
<![CDATA[re: Using metadata with MEF in Medium Trust]]>