x First time here? Check out the FAQ
Join us a the Umbraco event of the year - get your Codegarden 14 early bird ticket today

Medium Trust with Umbraco 4.0.x

    Umbraco being open-source and all, I've taken it upon myself to attempt to get Umbraco running in Medium Trust (shared hosting accounts). We're in an economic downturn (I'm in the UK and we're still in recession, while everyone else recovers) and I've had to downscale from a dedicated server to using shared hosting so it was a choice between hacking away at Umbraco source code or reverting to DotNetNuke with it's not-so-nice skinning API...

    Enough pre-amble. Here's the issues I came up against and how I fixed them.

    1. Problem: ImageManipulation library doesn't run in Medium Trust because it makes use of unsafe methods.
      Solution: Download updated ImageQuantization library by Brendan Tompkins, remove all but three files - Quantizer.cs, OctreeQuantizer.cs and PalleteQuantizer.cs. Update namespaces to use umbraco.imaging.ImageManipulation, build, and dump the resulting ImageManipulation.dll into your Umbraco /bin folder. See here for one I made earlier (download the ImageManipulation.zip file attached to the Codeplex work item).
    2. Problem: RoleProvider and MemberProvider not working with a horribly generic "Request failed" error.
      Solution: This one's a bit more in-depth. The umbraco.providers namespace has a utility class for shared features amongst all provider classes, called SecUtility, which has a method called GetDefaultAppName(). This attempts to call Process.GetCurrentProcess() which is not allowed under Medium Trust.
      I tried to add this line of code:

      if (string.IsNullOrEmpty(applicationVirtualPath) && 
      GlobalSettings.UseMediumTrust == false &&
      GlobalSettings.ApplicationTrustLevel != AspNetHostingPermissionLevel.Medium) {}

      However, this still included the line of code Process.GetCurrentProcess() which when built forced the whole compiled library to require Full Trust. Eventually removed the call to GetCurrentProcess and also updated the preceding line to use HostingEnvironment.ApplicationVirtualPath (thanks to Neils for spotting this one). Rebuilt and dumped umbraco.providers.dll into my /bin folder.
    3. Problem: Another "Request failed" error, this time on the web.config handlers for Umbraco channels.
      Solution: The current XMLRPC.Net module used in Umbaco (version 2.2.x) required FileIOPermission on something outside the application root which is not allowed in Medium Trust. Downloaded and built XMLRPC.Net v2.4.0 (which works in Medium Trust), dumped into /bin folder, updated references in source (or you can just add an assemblyBinding redirect in your web.config).
    4. Problem: Getting a SecurityException during installation, when various steps try to save connection strings and config settings to the web.config.
      Solution: GlobalSettings.SaveSetting() in umbraco.businesslogic was trying to use ConfigurationManager.OpenMappedExeConfiguration(), which attempts to not only load a given .config file, but also all other .config files from which it inherts. For web.config files, this happens to include machine.config, and therefore the library attempts to request Read permission on the machine.config, which fails in Medium Trust, as do any other methods to access configuration files as all web.configs inherit from machine.config. Replaced with a batch of XmlDocument magic for updating appSettings, rebuilt umbraco.businesslogic and dumped into /bin folder.
    5. Problem: <msxml:script> blocks won't work in Medium Trust.
      Solution: MSDN explains why <msxml:script> blocks are not allowed in Medium Trust as they potentially become a security vulnerability. This is a major problem for Umbraco as a lot of people use these extensions to write utility helpers for their XSLT macros, including XSLTsearch. What's even more confusing is that Microsoft claim that use of the AddExtensionObject requires full trust (which isn't true cause I've tested umbraco.library functions using Blog4Umbraco XSLT macros and they work just fine so AddExtensionObject must be working).
      The workaround is to have all XSLT helper methods declared as .NET assemblies (which is allowed under Medium Trust) - however, not everyone wants to be forced to use a compiled assembly. Here's the trick - all files inside the App_Code directory of your web application are compiled at runtime, it's the only place in a .NET application where dynamic compilation really occurs unless you are still using .as*x.cs files, in which case, shame on you for not using good coding practices and severely reducing your website disk space footprint. However, if it's just .cs and .vb files, how can these be turned into assemblies that can then be accessed as XSLT extension objects?
      One line of code in macro.cs in umbraco,presentation does the trick:

      Assembly.Load("__code")

      This will load the App_Code classes and treat them as precompiled assemblies. A little more work and this now allows you to create any code file in your App_Code folder which at runtime will be XSLT extension-accessible providing you add a new attribute, [XsltExtension()], to your class.
      For your class and code to be usable as XSLT extension methods, your class must have:
      • A zero-parameter constructor like so:

        namespace MyNamespace {
        [XsltExtension]
        public class MyClass {
        public MyClass() { }
        // Helper methods here
        }
        }
      • Helper methods must be public static. Your class must not be static!
    6. Your extension class and methods will then be accessible using xmlns:myprefix="urn:MyNamespace.MyClass" and you can call the public methods using <xsl:value-of select="myprefix:MyFunction()" />. Don't forget to also update your exclude-result-prefixes="msxml umbraco.library myprefix" so you don't get namespace declarations in your output which will then break your X/HTML compliance. :-)
    7. Problem: SQL Installer fails with the error "Cannot upgrade" when starting from a blank database.
      Solution: I finally managed to get the Umbraco SqlInstaller to pick up the updated database script (old version was 4.0.0.5, Umbraco 4.0.3 uses 4.0.0.12). Rebuilt and tested to work AOK, although I have since discovered (thanks to Doug Robar) that VistaDB requires Full Trust so Medium Trust will only function with SQL Server or MySQL (which most shared hosting accounts should offer so most users should be OK).
    8. Problem: After installing Blog4Umbraco (the install process works just fine on Medium Trust), I get a "Request failed" when I go to the content root of my site and it attempts to load CreatePost.ascx.
      Solution: I'm still working on this one, although I think it has something to do with a bit of code trying to change a QueryString value.

    Kudos to Brendan Tompkins for refactoring his ImageQuantization library to not use unsafe methods, and Charles Cook for fixing XMLRPC.Net so it works in Medium Trust.