System.Security.SecurityException accessing TermSet

During some upgrade testing, a customer found one of their custom controls not working in the 2010 environment.  They had built out a custom search web part that contained a custom property picker control.  The custom property picker control allowed users to leverage the Picker.aspx page to select specific properties that are associated with a profile property, like Skills.  This was no longer working in SharePoint 2010 as these user profile properties are now mapped to TermSets.  We tried switching the code over to using the TermSet for the Profile Property.  Something similar to the following:

    1: SPServiceContext context = SPServiceContext.GetContext(SPContext.Current.Site);
    3: ProfileSubtypeManager psm = ProfileSubtypeManager.Get(context);
    5: //Get the UserProfile subtype
    6: ProfileSubtype subType = psm.GetProfileSubtype("UserProfile");
    8: //Get the Skills property by URI
    9: ProfileSubtypeProperty prop = subType.Properties.GetPropertyByURI("urn:schemas-microsoft-com:sharepoint:portal:profile:SPS-Skills");
   11: if (prop.CoreProperty != null)
   12: {
   13:     if (prop.CoreProperty.TermSet != null)
   14:     {
   15:         //Do something with the TermSet
   16:     }
   17: }

This code worked fine in a Visual Web Part, but once we switched their custom control over to the TermSet, we started getting a System.Security.SecurityException.  I disabled custom errors in the web.config to get the exception message which was:

System.Security.SecurityException: That assembly does not allow partially trusted callers.

This exception was being thrown on the line that accesses the TermSet of the property.  The stack was also pointing to classes in the Microsoft.SharePoint.Taxonomy.dll when the SecurityException was thrown.

To get a better handle on why this was happening, I looked at the markup of the Picker.aspx page where their UserControl was being loaded from.  This page has the following Page declaration:

<%@ Page Language=”C#” Inherits=”Microsoft.SharePoint.ApplicationPages.Picker” … %>

The Microsoft.SharePoint.ApplicationPages.dll holds the Picker class, and is located in the _app_bin directory under the Web Application’s Physical Path.  The main thing to note here is that the DLL is not in the GAC.  In my case, this DLL is located at :  C:\Inetpub\wwwroot\wss\VirtualDirectories\SP2010Portal\_app_bin

The exception is occurring in calls to the TermSet classes.  These classes are in the Microsoft.SharePoint.Taxonomy.dll file, which is in the GAC.  Since Microsoft.SharePoint.ApplicationPages.dll is not in the GAC, and SharePoint does not run under full trust, we need to check the Microsoft.SharePoint.Taxonomy.dll file to ensure it has the AllowPartiallyTrustedCallers attribute applied to it.  The exception is indicating that the attribute will not be there, but it’s always good to make sure. 

In order to see the attribute, you can use ILDASM on a machine that has Visual Studio installed.  Here are the steps to check for the attribute:

  1. Start, All Programs, Microsoft Visual Studio 2010, Visual Studio Tools, Visual Studio Command Prompt
  2. Type : ILDASM
  3. Press <Enter>
  4. In ILDASM, select File, then Open
  5. Navigate to C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI
  6. Open Microsoft.SharePoint.Taxonomy.dll
  7. Double-click Manifest
  8. Click Find
  9. Search for : AllowPartiallyTrustedCallers 

What you’ll find is that this attribute is missing.  This means that you cannot call into the Taxonomy classes unless your DLL is fully trusted.  You can follow the above steps on using ILDASM with the Microsoft.SharePoint.dll to see what the attribute looks like when it is there.

Since this was a UI scenario where they wanted users to be able to select a valid term, we switched their web part to use the TaxonomyWebTaggingControl provided by SharePoint 2010.  This control leverages the TaxonomyField to render a picker control for selecting terms from a TermSet.  In the sample below, we’re taking the TermSet linked to the Skills UserProfile property, and associating it to a TaxonomyWebTaggingControl.  The control is then added to a PlaceHolder control in the web part.

    1: SPServiceContext context = SPServiceContext.GetContext(SPContext.Current.Site);
    3: ProfileSubtypeManager psm = ProfileSubtypeManager.Get(context);
    4: ProfileSubtype subType = psm.GetProfileSubtype("UserProfile");
    5: ProfileSubtypeProperty prop = subType.Properties.GetPropertyByURI("urn:schemas-microsoft-com:sharepoint:portal:profile:SPS-Skills");
    6: if (prop.CoreProperty != null)
    7: {
    8:     if (prop.CoreProperty.TermSet != null)
    9:     {
   10:         TaxonomyWebTaggingControl skillTerms = new TaxonomyWebTaggingControl();
   11:         skillTerms.TermSetList = prop.CoreProperty.TermSet.Id.ToString();
   12:         skillTerms.SSPList = prop.CoreProperty.TermSet.TermStore.Id.ToString();
   14:         PlaceHolder skillPlaceHolder = this.FindControl("skillPlaceHolder") as PlaceHolder;
   15:         if (skillPlaceHolder == null)
   16:             throw new System.Exception("Can not allocate skillPlaceHolder on the page.");
   17:         else
   18:             skillPlaceHolder.Controls.Add(skillTerms);
   19:     }
   21: }