Shazwazza

Shannon Deminick's blog all about .Net, Umbraco & Web development

Sql script for changing media paths or virtual directories in Umbraco

May 14, 2013 23:11 by Shannon Deminick

When you upload media in Umbraco it stores the absolute path to the media item in the database. By default the path will look something like:

/media/12335/MyImage.jpg

However, if you are running Umbraco in a virtual directory the path will also include the virtual directly prefix. For example:

/MyVirtualDirectory/media/12335/MyImage.jpg

So you can imagine that some issues might arise if you already have data in your Umbraco install and then wanted to change virtual directory paths, or even change the media location path (umbracoMediaPath) in the web.config.

Luckily it’s easily solved with a quick SQL script. These scripts will update the path stored in Umbraco created by any property type that is of a data type with an ‘upload control’ property editor.

When moving to a virtual directory

Here’s a quick script to run against your current install if you are moving from a normal installation to using a virtual directory. Note: You will need to replace all instances of ‘MyVirtualDirectory’ to be your vdir path!

update cmsPropertyData 
set dataNvarchar = '/MyVirtualDirectory' + dataNvarchar
where id in
(select cmsPropertyData.id from cmsPropertyData
inner join cmsPropertyType on cmsPropertyData.propertytypeid = cmsPropertyType.id
inner join cmsDataType on cmsPropertyType.dataTypeId = cmsDataType.nodeId
where cmsDataType.controlId = '5032a6e6-69e3-491d-bb28-cd31cd11086c'
and cmsPropertyData.dataNvarchar is not null
and SUBSTRING(cmsPropertyData.dataNvarchar, 0, LEN('/MyVirtualDirectory') + 1) <> '/MyVirtualDirectory')

When moving from a virtual directory

Here’s the script to run if you are currently running in a virtual directory and want to move to a non-virtual directory. Note: You will need to replace all instances of ‘MyVirtualDirectory’ to be your vdir path!

update cmsPropertyData 
set dataNvarchar = SUBSTRING(dataNvarchar, LEN('/MyVirtualDirectory') + 1, LEN(dataNvarchar) - LEN('/MyVirtualDirectory'))
where id in
(select cmsPropertyData.id from cmsPropertyData
inner join cmsPropertyType on cmsPropertyData.propertytypeid = cmsPropertyType.id
inner join cmsDataType on cmsPropertyType.dataTypeId = cmsDataType.nodeId
where cmsDataType.controlId = '5032a6e6-69e3-491d-bb28-cd31cd11086c'
and cmsPropertyData.dataNvarchar is not null
and SUBSTRING(cmsPropertyData.dataNvarchar, 0, LEN('/MyVirtualDirectory') + 1) = '/MyVirtualDirectory' )

Moving to a different virtual directory?

If you want to move to a different virtual directory, you can combine the above 2 scripts… first move from a virtual directory back to normal, then move to the new virtual directory.

The above procedures would work as well if you were to change the umbracoMediaPath app setting in the web.config … though most people wont change that or even know about it ;)

Razor + dynamic + internal + interface & the 'object' does not contain a definition for 'xxxx' exception

April 11, 2013 14:49 by Shannon Deminick

I’ve come across this strange issue and decided to blog about it since I can’t figure out exactly why this is happening it is clearly something to do with the DLR and interfaces.

First, if you are getting the exception: 'object' does not contain a definition for 'xxxx' it is related to either an object you have being marked internal or you are are using an anonymous object type for your model (which .Net will always mark as internal).

Here’s a really easy way to replicate this:

1. Create an internal model

internal class MyModel
{
public string Name {get;set;}
}

2. Return this model in your MVC action

public ActionResult Index()
{
return View(new InternalTestModel("Shannon"));
}

3. Make your view have a dynamic model and then try to render the model’s property

@model dynamic
<h1>@Model.Name</h1>

You’ll get the exception:

Server Error in '/' Application.

'object' does not contain a definition for 'Name'

So even though the error is not very informative, it makes sense since Razor is trying to access an internal class.

Try using a public interface

Ok so if we want to keep our class internal, we could expose it via a public interface. Our code might then look like this:

public interface IModel 
{
string Name {get;}
}
internal class MyModel : IModel
{
public string Name {get;set;}
}

Then we can change our view to be strongly typed like:

@model IModel
<h1>@Model.Name</h1>

And it will work, however if you change your view back to be @model dynamic you will still get the exception. Pretty sure it’s because the DLR is just binding to the instance object and doesn’t really care about the interface… this makes sense.

Try using an abstract public class

For some reason if you make your internal class inherit from a public abstract class that implements the same interface you will not get this exception even though the object instance you are passing to razor is internal. For example with this structure:

public interface IModel 
{
string Name {get;}
}
public abstract class ModelBase : IModel
{
public abstract Name {get;}
}
internal class MyModel : IModel
{
public override string Name {get;set;}
}

You will not get this error if your view is @model dynamic.

Strange!

I’m sure there’s something written in the DLR spec about this but still seems strange to me! If you are getting this error and you aren’t using anonymous objects for your model, hopefully this might help you figure out what is going on.

Examine 1.5.1 released

April 5, 2013 17:59 by Shannon Deminick

I’ve created a new release of Examine today, version 1.5.1. There’s nothing really new in this release, just a bunch of bug fixes. The other cool thing is that I’ve finally got Examine on Nuget now. The v1.5.1 release page is here on CodePlex with upgrade instructions… which is really just replacing the DLLs.

Its important to note that if you have installed Umbraco 6.0.1+ or 4.11.5+ then you already have Examine 1.5.0  installed (which isn’t an official release on the CodePlex page) which has 8 of these 10 bugs fixed already.

Bugs fixed

Here’s the full list of bugs fixed in this release:

UmbracoExamine

You may already know this but we’ve moved the UmbracoExamine libraries in to the core of Umbraco so that the Umbraco core team can better support the implementation. That means that only the basic Examine libraries will continue to exist @ examine.codeplex.com. The release of 1.5.1 only relates to the base Examine libraries, not the UmbracoExamine libraries, but that’s ok you can still upgrade these base libraries without issue.

Nuget

There’s 2 Examine projects up on Nuget, the basic Examine package and the Azure package if you wish to use Azure directory for your indexes.

Standard package:

PM> Install-Package Examine

Azure package:

PM> Install-Package Examine.Azure

 

Happy searching!

New Examine updates and features for Umbraco

March 5, 2013 23:42 by Shannon Deminick

It’s been a long while since Examine got some much needed attention and I’m pleased to say it is now happening. If you didn’t know already, we’ve moved the Umbraco Examine source in to the core of Umbraco. The underlying Examine (Examine.dll) core will remain on CodePlex but all the Umbraco bits and pieces which is found in UmbracoExamine.dll are in the Umbraco core from version 6.1+. This is great news because now we can all better support the implementation of Examine for Umbraco. More good news is that even versions prior to Umbraco 6.1 will have some bugs fixed (http://issues.umbraco.org/issue/U4-1768) ! Niels Kuhnel has also jumped aboard the Examine train and is helping out a ton by adding his amazing ‘facet’ features which will probably make it into an Umbraco release around version 6.2 (maybe 6.1, but still need to do some review, etc… to make sure its 100% backwards compatible).

One other bit of cool news is that we’re adding an official Examine Management dashboard to Umbraco 6.1. In its present state it supports optimizing indexes, rebuilding indexes and searching them. I’ve created a quick video showing its features :)

Examine management dashboard for Umbraco

Using IoC with Umbraco & MVC

October 31, 2012 17:08 by Shannon Deminick

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.

Native MVC support in Umbraco coming very soon!

October 30, 2012 23:07 by Shannon Deminick

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!

MVC in Umbraco v4

June 18, 2012 05:33 by Shannon Deminick

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.

Taming the BuildManager, ASP.Net Temp files and AppDomain restarts

March 28, 2012 06:14 by Shannon Deminick

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.

Hijacking Umbraco routes

March 7, 2012 05:02 by Shannon Deminick

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!  :)

Registering custom components in IoC for Umbraco 5 plugins

January 2, 2012 01:23 by Shannon Deminick

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.

Recent Tweets

Twitter May 14, 14:14
blogged: script to fix media paths when changing vdirs or media root paths in #umbraco http://t.co/w1csEtceu1

Twitter May 10, 18:27
@darrenferguson probably better discussed on a forum thread I think :-) @sitereactor

Twitter May 10, 17:55
@darrenferguson and won't work in LB cuz a servers file will b stale when it goes to sleep @sitereactor

Twitter May 10, 17:53
@darrenferguson sorry, bad wording... You'd have to write that feature but it'd be pretty simple @drobar @sitereactor

Twitter May 10, 08:34
@sitereactor ... wouldn't work for LB scenarios though @darrenferguson @drobar

Follow me