The Software Artist | Code is a form of art.

Dec/09

27

Running SharpArchitecture in medium trust

As anyone with experience with medium trust will tell you, it can be a pain. It imposes certain security restrictions that a lot of code takes for granted, with reflection probably being the most common offender. SharpArchitecture is one such framework that doesn’t run in medium trust out of the box. This post describes how to get it and its Northwind sample application running in medium trust, using the SharpArchitecture 1.0 Q3 release.

First, a word of caution: I’m in the early stages of investigating SharpArch, especially in medium trust. One of the main changes we must make is to recompile all of the SharpArch dlls and dependencies with the AllowPartiallyTrustedCallers assembly attribute, so that they can be used in a medium trust environment. But simply adding this attribute to the assemblies doesn’t mean that the code in the assemblies is appropriate for use in a medium trust environment. So it’s possible that some of these components contain code which will raise SecurityPermission exceptions in medium trust. I only encountered one such issue with NHibernate.Validator, but deeper use of these components may uncover further issues. I will update this post with any new info as I begin building a real application running under medium trust with SharpArch and its dependencies.

The steps are pretty simple, the main thing we have to do is add the AllowPartiallyTrustedCallers attribute to all of the assemblies that are referenced by the Northwind sample app. One of the dependencies, NHibernate.Validator, will also require a small code change in order to run in medium trust properly. I’ve filed a bug against NHV for this problem, hopefully it will be fixed in a future version.

This is not a full step-by-step tutorial, these instructions assume you’re already familiar with pulling source from SVN servers, building projects with nant, etc. If you’re not familiar with these topics, there are many sources of info on the net that can explain them much better than I. So, let’s get started.

Castle

Several components from Castle are used by the Northwind app, both directly and indirectly, so we need to rebuild it first. Until recently, using NHibernate in medium trust required disabling lazy loading because Castle.DynamicProxy2 wouldn’t work properly in medium trust. Some recent fixes to DynamicProxy have remedied this, so we can now use NHibernate with lazy loading in medium trust. This is great, but unfortunately it means we must use a different version of the Castle components than what is included with SharpArch. This doesn’t cause a problem by itself, but we’ll have to rebuild basically all of SharpArch’s dependencies because of it.

The three Castle projects we must rebuild are Castle.Core, Castle.DynamicProxy2, and Castle.Windsor.

Castle.Core

  1. Pull the source from https://svn.castleproject.org/svn/castle/Core/trunk
  2. Build with the following command line parameter to add the AllowPartiallyTrustedCallers attribute to the assembly: -D:assembly.allow-partially-trusted-callers=true. Read the Castle docs for other parameters to the build script, you may also want to build without running tests and build the release config. Here is what I use to build a release build with AllowPartiallyTrustedCallers set, and to skip running the unit tests:
    nant -D:assembly.allow-partially-trusted-callers=true -D:common.testrunner.enabled=false -D:project.config=release
  3. The output files are located at build\net-3.5\release.

Castle.DynamicProxy

  1. Pull the source from https://svn.castleproject.org/svn/castle/DynamicProxy/trunk
  2. Copy the newly built Castle.Core.dll to \lib\net-3.5
  3. Build with nant. This project has the APTC attribute set already, so you do not need to provide it on the command line. You can use the same parameters as above to skip the tests and build a release build. The output files are located in build\net-3.5\release.

Castle.Windsor

  1. Pull the source from https://svn.castleproject.org/svn/castle/InversionOfControl/trunk
  2. Copy Castle.Core.dll and your new Castle.DynamicProxy2.dll to \lib\net-3.5
  3. Build with nant, providing the APTC command line argument. You can use the same command line as with Castle.Core, and the output files are once again located in build\net-3.5\release.

CommonServiceLocator.WindsorAdapter

Now that we’ve built Castle we can build the other dependencies that reference it, starting with the WindsorAdapter for the Common Service Locator from Microsoft’s Patterns & Practices group:

  1. Download the source from http://commonservicelocator.codeplex.com/wikipage?title=Castle%20Windsor%20Adapter
  2. Copy all of the newly built Castle dlls (Castle.Core.dll, Castle.DynamicProxy2.dll, Castle.MicroKernel.dll, and Castle.Windsor.dll) to the SharedLibs directory.
  3. Open the WindsorAdapter project in Visual Studio and edit the Properties\AssemblyInfo.cs file by adding the following two lines:
    using System.Security;
    [assembly: AllowPartiallyTrustedCallers]
    
  4. Build the project

NHibernate

  1. Pull the source from https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk
  2. Copy the newly built Castle.Core.dll and Castle.DynamicProxy2.dll to \nhibernate\lib\net\3.5
  3. Build with nant. This project already has the APTC attribute set, so you can use the same command line given for Castle.DynamicProxy. The output files will be located at build\<version>\bin\net-3.5. At the time of writing, the version is “NHibernate-3.0.0.Alpha1″.

NHibernate.Validator

  1. Pull the source from http://sourceforge.net/projects/nhcontrib/files/NHibernate.Validator. I use the 1.2.0 CR1 release: http://sourceforge.net/projects/nhcontrib/files/NHibernate.Validator/1.2.0%20CR1/NHibernate.Validator-1.2.0.CR1-src.zip/download.
  2. Copy the new Castle.Core.dll, Castle.DynamicProxy2.dll, and NHibernate.dll to lib.
  3. Edit NHibernate.Validator/Engine/InvalidMessageTransformer.cs, line 80 to:
        return validatorDef.Tags == null || validatorDef.Tags.Count == 0 ? new List<object>() : validatorDef.Tags;
        

    At some point NHV may be updated so that this step is not required.

  4. Build with nant: nant -D:skip.tests=true -D:project.config=release. The output files will be located in build\NHibernate.Validator-1.2.0.CR1\bin\net-3.5

FluentNHibernate

  1. Download the source from http://fluentnhibernate.org/downloads – I used the source download link to 1.0.0.600, which is the latest build at the time of writing: http://fluentnhibernate.org/downloads/fluentnhibernate-source-1.0.0.600.zip
  2. Copy the new Castle.Core.dll, Castle.DynamicProxy2.dll, NHibernate.ByteCode.Castle.dll, and NHibernate.dll to \tools\NHibernate
  3. Build src\FluentNHibernate.sln

Inflector.Net

  1. Download the source from http://andrewpeters.net/inflectornet/
  2. Open the solution in visual studio and add a new C# code file named AssemblyInfo.cs to the project, then add the following code to this file:
      using System.Security;
      [assembly: AllowPartiallyTrustedCallers]
      
  3. Build the Inflector.Net project

Microsoft.Web.Mvc

  1. The source for the Microsoft.Web.Mvc.dll assembly (MvcFutures) is part of the ASP.NET MVC source which can be downloaded at http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=24471
  2. Open the MvcFutures project at MVC-RTM\MVC\src\MvcFutures in Visual Studio and update Properties\AssemblyInfo.cs to add the AllowPartiallyTrustedCallers attribute with the following code:
      [assembly: AllowPartiallyTrustedCallers]
      
  3. The existing reference to System.Web.Mvc is a project reference to the MVC source in this download. Remove this reference and add a new reference to the released System.Web.Mvc, which should be in your GAC.
  4. Build the MvcFutures project
  5. The Microsoft.Web.Mvc.dll that SharpArch references is signed, so we must sign our new one. You can do so by executing the following in a Visual Studio command line. If you already have a key pair file, you can use that instead of creating a new one:

    sn -k myKey.snk
    ildasm /all /out=Microsoft.Web.Mvc.il Microsoft.Web.Mvc.dll
    ilasm /dll /key=sgKey.snk Microsoft.Web.Mvc.il

MvcContrib

  1. I use the MvcContrib 1.5 RC release which can be downloaded from http://mvccontrib.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=33777
  2. Copy the new Microsoft.Web.Mvc.dll to bin\aspnetmvc.
  3. Copy Castle.Core.dll, Castle.MicroKernel.dll, and Castle.Windsor.dll to bin\castle.
  4. The main MvcContrib project already has an AssemblyInfo file that includes the APTC attribute, but SharpArch includes two other assemblies from MvcContrib (MvcContrib.Castle and MvcContrib.FluentHtml) that do not have the APTC attribute set. MvcContrib.Castle is used by the Northwind sample app, while MvcContrib.FluentHtml is not, but we’ll go ahead and add the APTC attribute to both of these. Note that this is a good example of my cautionary note above. There may be code in these two projects which will fail in medium trust, although the Northwind sample app is able to use the WindsorControllerFactory from MvcContrib.Castle just fine. However, you may encounter problems if you attempt to use more from these two assemblies. Here’s how to add the APTC attribute to both:
    1. Open the MvcContrib solution in Visual Studio. The MvcContrib.FluentHtml project already has an AssemblyInfo file in its Properties folder. Open this file and add the following code:
        using System.Security;
        [assembly: AllowPartiallyTrustedCallers]
        
    2. Add an AssemblyInfo.cs file to the MvcContrib.Castle project and add the same code to it, then close Visual Studio.
  5. Build with nant: nant -D:project.config=release -D:runtests=false. The output location is build\net-3.5.win32-MVCContrib-release.

That’s it for the SharpArch dependencies, now we have to rebuild the SharpArch project itself.

SharpArchitecture

  1. Copy all newly built dependencies to bin:
    1. Castle.Core.dll
    2. Castle.DynamicProxy2.dll
    3. Castle.MicroKernel.dll
    4. Castle.Windsor.dll
    5. CommonServiceLocator.WindsorAdapter.dll
    6. FluentNHibernate.dll
    7. Inflector.Net.dll
    8. Microsoft.Web.Mvc.dll
    9. MvcContrib.Castle.dll
    10. MvcContrib.dll
    11. MvcContrib.FluentHtml.dll
    12. MvcContrib.TestHelper.dll
    13. NHibernate.ByteCode.Castle.dll
    14. NHibernate.dll
    15. NHibernate.Validator.dll
  2. Edit SharpArch.Tests/SharpArch.Web/CommonValidator/MvcValidationAdapterTests.cs to match latest NHibernate.Validator. The InvalidValue constructor requires a 6th argument in our newer version:
    invalidValues.Add(
        new ValidationResult(
            new InvalidValue("Message 1", typeof(TransactionAttribute), "Property1", null, null, null)));
    invalidValues.Add(
        new ValidationResult(
            new InvalidValue("Message 2", typeof(MvcValidationAdapter), "Property2", null, null, null)));
    invalidValues.Add(
        new ValidationResult(
            new InvalidValue("Message 3", GetType(), "Property3", null, null, null)));
    
  3. Edit the SharpArch.build file so that it adds the APTC to the automatically generated CommonAssemblyInfo.cs file, by adding the two highlighted lines below:
    <target name="version" description="Generate AssemblyInfo">
      <property name="version.build" value="${build.number}" if="${property::exists('build.number')}"/>
      <property name="version.revision" value="${build.vcs.number.1}" if="${property::exists('build.vcs.number.1')}" />
    
      <echo message="Marking build with version ${project.fullversion}" />
      <delete file="${solution.dir}/CommonAssemblyInfo.cs" failonerror="false"/>
      <asminfo output="${solution.dir}/CommonAssemblyInfo.cs" language="CSharp">
        <imports>
          <import namespace="System.Reflection" />
          <import namespace="System.Runtime.InteropServices" />
          <import namespace="System.Security" />
        </imports>
        <attributes>
          <attribute type="ComVisibleAttribute" value="false" />
          <attribute type="AssemblyVersionAttribute" value="${project.fullversion}" />
          <attribute type="AssemblyFileVersionAttribute" value="${project.fullversion}" />
          <attribute type="AssemblyInformationalVersionAttribute" value="${project.fullversion}" />
          <attribute type="AssemblyCopyrightAttribute" value="Copyright © ${company.name} ${datetime::get-year(datetime::now())}" />
          <attribute type="AssemblyCompanyAttribute" value="${company.name}" />
          <attribute type="AssemblyConfigurationAttribute" value="${project.config}" />
          <attribute type="AssemblyTrademarkAttribute" value="" />
          <attribute type="AssemblyCultureAttribute" value="" />
          <attribute asis="true" type="AllowPartiallyTrustedCallersAttribute" />
        </attributes>
        <references>
          <include name="System.dll" />
        </references>
      </asminfo>
    </target>
    
  4. Build with nant: nant -D:project.config=release

Now we’ve got a version of SharpArch and all its dependencies that will run in medium trust. Even if you have no interest in running the Northwind sample in medium trust, there are a few things we must do to a web app built with the SharpArch project template to enable it to run in medium trust. As such, I believe these instructions are applicable to any web app built with the SharpArch project template.

Northwind Sample

  1. Copy the newly built SharpArch*.dll files from the SharpArch\build directory to the SharpArch\bin directory. The Northwind project references these dlls from the SharpArch\bin directory.
  2. Edit src\NorthwindSample\CommonAssemblyInfo.cs to add the APTC attribute:
    using System.Security;
    [assembly: AllowPartiallyTrustedCallers]
    
  3. Open Northwind.sln in VS2008
  4. We have to make a few changes to the NHibernate configuration so that NHibernate will run properly in medium trust. One of these (reflection-optimizer) requires us to move the NH config out of its own file and into web.config. To move the config into web.config, in the Northwind.Web project:
    1. Add a config section declaration for the NH config section, I put mine right after the log4net section declaration:
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" requirePermission="false"/>
        <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" requirePermission="false" />
        
    2. Copy the <hibernate-configuration> section and all of its contents from NHibernate.config to somewhere in web.config, I put mine right above the log4net section.
    3. Open Global.asax.cs, go to the InitializeNHibernateSession() method, and remove the last parameter in call to NHibernateSession.Init() to tell NHibernate to get its config from web.config.
  5. Update the NH configuration info in web.config for use in medium trust:
    1. Remove the adonet.batch_size property, NHibernate update batching does not work in medium trust
    2. Add <reflection-optimizer use="false" /> as a child of <hibernate-configuration>. The reflection optimizer requires some reflection permissions that aren’t available in medium trust. Turning the reflection optimizer off will cause a performance decrease overall, although you may see a performance boost during app startup. See the NHibernate documentation here for more info.
    3. As per the SharpArch docs, add the current_session_context_class property with value managed_web. In my testing I didn’t find this necessary, but assuming the docs are up to date then it is their guidance to add it. You can see the NHibernate documentation here for more on this property.

    My final config section in web.config is as follows:

    <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
      <reflection-optimizer use="false" />
      <session-factory>
        <property name="connection.connection_string">Data Source=your_server;Database=Northwind;UID=username;pwd=password;</property>
        <property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
        <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
        <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
        <property name="show_sql">false</property>
        <property name="connection.release_mode">auto</property>
        <property name="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>
        <property name="current_session_context_class">managed_web</property>
    
        <!-- Mapping assemblies -->
        <!-- Can't map it for Fluent NHibernate here; instead, load the mapping assembly in Global.asax.cs.
        If you're still using HBMs, you can use the mapping here or pass the assembly via Global.asax.cs
        as well, just like you can do with the Fluent NHibernate assembly(s). -->
        <!-- mapping assembly="Northwind.Data" -->
      </session-factory>
    </hibernate-configuration>
    
  6. Set the app to use medium trust by adding <trust level="Medium" originUrl="" /> to the system.web section.
  7. Don’t forget to update the NH config with your Northwind database info.
  8. If you want to make use of the WCF part of the Northwind sample app, you’ll need to manually add the APTC attribute to the Northwind.Wcf\Properties\AssemblyInfo.cs file.
  9. Set Northwind.Web as the startup project, rebuild and run.

That’s it, the Northwind sample app should now run successfully in medium trust.

· · ·

19 comments

  • ASP.NET MVC Archived Blog Posts, Page 1 · December 28, 2009 at 4:40 pm

    [...] to VoteRunning SharpArchitecture in medium trust (12/27/2009)Sunday, December 27, 2009 from PaulAs anyone with experience with medium trust will tell you, it can [...]

  • Jim · January 31, 2010 at 11:31 am

    I should have done my homework on this issue beforehand – quite a few steps just to get this bad boy up and running on a normal hosted environment. Thank you so much for putting together the steps though – who know how long it would have taken me to do this if you hadn’t.

    Jim

  • Admin comment by Paul · January 31, 2010 at 1:22 pm

    Thanks, and no problem. This post could use a slight update – my fix to NHibernate.Validator is now in their source and there have been some official Castle releases recently (Windsor 2.1.1, DynamicProxy 2.2.0, and Core 1.2.0). I have updated my baseline to all of these and it was not as easy as it sounds, I should probably blog it before I forget it.

  • Luke · February 5, 2010 at 7:18 pm

    Hi Paul,

    Thanks for the post, saved me a lot of time!

    Have a couple hiccups, first being this exception after grabbing the latest from Castle trunk and following your steps:

    Could not load file or assembly ‘Castle.MicroKernel, Version=2.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc’ or one of its dependencies. The located assembly’s manifest definition does not match the assembly reference.

    Do you know perhaps why I’m getting this? The latest versions of Castle Windsor is 2.1, not sure what depends on 2.0.

    Thanks,

    Luke

  • Admin comment by Paul · February 7, 2010 at 12:34 pm

    Yes, this post is in need of an update, especially since these latest official Castle releases. Many of the assemblies used in a sharparch app have dependencies on the various castle assemblies. It could be CommonServiceLocator.WindsorAdapter, MvcContrib.Castle, NHibernate.ByteCode.Castle, SharpArch.Web.Castle, etc. Your best bet is to use .NET Reflector to inspect the dependencies of all of the dlls in your Web project’s bin folder and find which of them have references to the Castle dlls. I’ll try to find some time to update this post.

  • Luke · February 8, 2010 at 6:12 pm

    Thanks Paul, so far so good. I followed your advice by using reflector on my version of Sharp to see the Castle dependencies and re-downloaded them from the trunk and followed your steps again.

    Castle.Core – 1.1.0.0
    Castle.DynamicProxy2 – 2.1.0.0
    Castle.MicroKernel – 2.0.0.0
    Castle.Windsor – 2.0.0.0

    I was getting Reflection exceptions so I downloaded my server’s custom config settings (my shared server operates in modified medium trust) and now it works.

    Thanks!

  • Admin comment by Paul · February 9, 2010 at 10:50 am

    Glad you got it working. Does your host make your shared hosting config available to you? Is there some common method of being able to download the server’s config, built into IIS or something like that? I have a project being hosted on GoDaddy shared hosting, and I’m able to develop for it using a custom trust level that is basically medium trust + socket permissions (for MySql), but I’d like to exactly replicate their configuration if possible. So far I haven’t found any information on exactly what their config is.

  • Luke · February 9, 2010 at 4:29 pm

    I’m hosted on Rack Space’s cloud sites and a quick google fortunately landed me here, http://cloudsites.rackspacecloud.com/index.php/Overview_of_modified_Medium_Trust. At the bottom they have a link to download the .config file.

    Perhaps Go Daddy has this available if you talk to tech support, as I couldn’t find it.

    Cheers,

    Luke

  • Mazhar · February 11, 2010 at 8:06 am

    Great topic. Medium Trust seems to be the nightmare for NHibernate. I have followed your suggestions and was able to setup it successfully. Thanks for sharing such a good topic.

  • Ben Scott · March 10, 2010 at 7:32 am

    Hi Paul,

    I’ve nearly got it to work with the current versions of the entire stack. One final hang up which I’m hoping you’ve encountered is to do with the InitializeServiceLocator() method in Global.asax. It’s still throwing the SecurityException but I’m having trouble attaching a debugger. Did you run into the same issue?

    Thanks,
    Ben.

  • Ben Scott · March 10, 2010 at 8:24 am

    Hey Paul,

    Nevermind, I found it! On the 3rd complete rebuild I found that the -D:assembly.allow-partially-trusted-callers=true on some of the Castle projects (Castle.MicroKernel and Castle.Windsor) didn’t work. I had to manually modify the AssemblyInfo.cs for both projects to solve my issue.

    Thanks again for blogging this. You have literally saved me a week’s work.

    Ben.

  • Admin comment by Paul · April 1, 2010 at 10:20 am

    Glad you got it working Ben, and sorry for not responding for so long, I’ve been busy at work and haven’t had much time for this blog or the personal project I’m working on with SharpArch. Hoping to pick it back up soon though.

  • SharpArchitecture 1.5 in medium trust · The Software Artist · May 16, 2010 at 11:50 am

    [...] previous post on running S#arpArchitecture 1.0 in medium trust seemed to be helpful to a few, so here are [...]

  • Laury · June 2, 2010 at 2:02 pm

    This is great. Such a useful post. Thanks Paul. Saved me a lot of time.

    Nevertheless, I still can make it work entirely because I’m getting an exception that says “Request for the permission of type ‘System.Security.Permissions.ReflectionPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′ failed.”.

    My site is in godaddy (figures). I made this build work after my third try and I just don’t want to give this up being so close to resolve it and bit godaddy’s medium trust. If anyone can help me would be great.

    Cheers

  • Laury · June 2, 2010 at 3:55 pm

    btw, I analyzed the stack trace and apparently I can’t create a proxy… my code breaks here
    NHibernate.ByteCode.Castle.ProxyFactory.GetProxy(Object id, ISessionImplementor session) +416. And the InnerException message says “Creating a proxy instance failed”

    Does this mean that NHibernate.ByteCode.Castle or Castle.DynamicProxy don’t have APTC on? because I made it, more than once, for days!! I even know all the process by heart.

    Can someone help me please?

  • Admin comment by Paul · June 3, 2010 at 9:31 pm

    @Laury:

    If you were having a problem with an assembly lacking the APTC attribute then you’d get an assembly loading error. I don’t think that’s the case here. Make sure you’ve set the reflection-optimizer to false in your NH config.

  • Laury · June 3, 2010 at 11:44 pm

    Thanks for the answer Paul.
    And yes, it’s false. I’ve tried everything already (well it’s should be working if so). I think I’m about to throw the towel already.

    I read something about ProxyGenerator though, but isn’t that NHibernate.ByteCode.Castle.ProxyFactoryFactory is for? I’ll be playing with that.

    Thanks anyway

  • Laury · June 4, 2010 at 12:53 pm

    What would you know. I added .Not.LazyLoad() to every reference in my mapping files and it works now,

    In addition, some lines for any of you to be aware of what medium trust can affect despite NHibernate. In my local version I have medium trust on and:

    - I can cache a byte[] which represent an image on my site, well, in godaddy, apparently, this have been restricted in medium trust. All the images on my site doesn’t show.

    - Some css doesn’t work (I don’t know why, css doesn’t represent a treat of any kind on securities). In Conclusion it’s time to get my business somewhere else.
    This 2 first observations works locally, in Godaddy not.

    This last one doesn’t work anywhere:
    - Well, with Ajax, I internally render a View from the Controller and display the html returned on a division tag (that’s the beauty of mvc). Well, my renderpartialtostring process doesn’t work and break with an exception in System.Security.Permissions.SecurityPermission. I bet that is when it tries to render the view by using the framework.

    In conclusion, run as far as you can from GoDaddy if you are using ASP.NET 2.0/3.0/3.5. They support full trust only in ASP.NET 1.1

    Cheers

  • Admin comment by Paul · June 4, 2010 at 1:51 pm

    @Laury:

    Check which version of Castle DynamicProxy you’re using. The version that was included with S#arp 1.0 did not work in medium trust, but later versions do. You shouldn’t have to disable lazy loading completely. Also note that this post is rather out of date, the Castle source is now in github. See my post on S#arp 1.5 and medium trust for more details.

    Also, I’m afraid I’m not much help on your other issues with GoDaddy. I host a site there too, and while I’m not running a production S#arp site there I am in the process of building one to run on my GoDaddy account, and so far I’ve had success getting it to run there. There are some things I can’t do (like use AutoMapper, for instance), but the basic S#arp site works OK.

    Hope you get everything working.

Leave a Reply

<<

>>

Theme Design by devolux.nh2.me