From the outside in

The blog of Iain Angus

DefaultSiteCollectionTermStore == null

Between writing the previous post about provisioning Managed Metadata fields declaratively we decided to remove the hard-coded term store name shown below

var termStore = session.TermStores["Managed Metadata Service"];

and replace it with

TermStore termStore = session.DefaultSiteCollectionTermStore;

We found that while the solution worked locally when we deployed the feature to the SharePoint 2010 UAT server it didn’t work. Turns out that the DefaultSiteCollectionTermStore was null.

After much scratching of heads we narrowed the issue down the way the Managed Metadata Service Proxy had been set up during the installation of the UAT SharePoint server. The IT team responsible for building the UAT servers used PowerShell to automate the building of the server. For the Managed Metadata Service this had a particular impact.

If you highlight the Managed Metadata Service Connection in Central Administration, then click Properties as shown below:

image

you will see the properties available…

image

On our development PCs, which had been setup using the Configuration Wizard, all of the available check boxes above were ticked. On the UAT server the opposite was true. Dutifully we ticked all the boxes, hit OK and tried again. Still no joy, so we set up another site collection and activated the feature. This time the feature worked as expected.

Activating the default storage location for keywords and column specific term sets only works for site collections created after the options have been selected (no surprise). At this point we haven’t been able to work out how to associate the default storage with an existing site collection and the easiest option was to delete the site collection, set up a new one and activate the required features.

Declaratively Provision Managed Metadata Column in SharePoint 2010

As part of a project I have been working on we wanted to assign categories to items in SharePoint 2010 and decided to use Managed Metadata. Wictor Wilén has a good post explaining what Managed Metadata is and how to set it up. Like Wictor, I also prefer to provision site columns and content types using a combination of declarative CAML and feature receivers. I followed the Wictors post but found he didn’t add the extra steps required to make the solution work.

I’ve outlined the steps we took to provision a managed metadata column to a site content type.

Step 1 - Create a TaxonomyField and a Note field

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Field ID="{087C759A-7BD2-4B66-9CF5-277A3399636D}"
    Type="TaxonomyFieldType"
    DisplayName="MMSCategories"
    ShowField="Term1033"
    Required="TRUE"
    EnforceUniqueValues="FALSE"
    Group="_Custom"
    StaticName="MMSCategories"
    Name="MMSCategories"
     />
  <Field ID="{437B0ED2-A31B-47F7-8C69-6B9DE2C4A4F6}"
    Type="Note"
    DisplayName="MMSCategories_0"
    StaticName="MMSCategoriesTaxHTField0"
    Name="MMSCategoriesTaxHTField0"
    ShowInViewForms="FALSE"
    Required="FALSE"
    Hidden="TRUE"
    CanToggleHidden="TRUE"
    />
</Elements>
Step 2 - Add the TaxonomyField and Note Field to a content type
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <!-- Parent ContentType: Item (0x01) -->
  <ContentType ID="0x0100aa33de693811427c886a5d27f17ed23d"
               Name="Taxonomy Spike - MMSContentType"
               Group="Custom Content Types"
               Description="My Content Type"
               Inherits="TRUE"
               Version="0">
    <FieldRefs>
      <FieldRef ID="{437B0ED2-A31B-47F7-8C69-6B9DE2C4A4F6}" Name="MMSCategoriesTaxHTField0"/>
      <FieldRef ID="{087C759A-7BD2-4B66-9CF5-277A3399636D}" Name="MMSCategories"/>
    </FieldRefs>
  </ContentType>
</Elements>

Step 3 - Wire up the Note field to the TaxonomyField using a feature receiver

The TaxonomyField has a member called TextField, with the following remark on the MSDN page…

“Every TaxonomyField object contains a related hidden text field that contains a string representation of the taxonomy field value. The hidden text field is identified by the GUID returned by this property.”

…so as well as the defining the Taxonomy Field we also need to define something to store the string representation.

   1:  public override void FeatureActivated(SPFeatureReceiverProperties properties)
   2:  {
   3:      SPSite site = properties.Feature.Parent as SPSite;
   4:      Guid fieldId = new Guid("{087C759A-7BD2-4B66-9CF5-277A3399636D}");
   5:      if (site.RootWeb.Fields.Contains(fieldId))
   6:      {
   7:          TaxonomySession session = new TaxonomySession(site);
   8:   
   9:          if (session.TermStores.Count != 0)
  10:          {
  11:              var termStore = session.TermStores["Managed Metadata Service"];
  12:              var group = termStore.Groups["Test Store"];
  13:              var termSet = group.TermSets["Categories"];
  14:              TaxonomyField field = site.RootWeb.Fields[fieldId] as TaxonomyField;
  15:              // Connect to MMS 
  16:              field.SspId = termSet.TermStore.Id;
  17:              field.TermSetId = termSet.Id;
  18:              field.TargetTemplate = string.Empty;
  19:              field.AnchorId = Guid.Empty;
  20:              field.TextField = new Guid("{437B0ED2-A31B-47F7-8C69-6B9DE2C4A4F6}");
  21:              field.Update(true);
  22:          }
  23:      }
  24:  }

Line 20 is the important one, this is the code that wires the Note field created declaratively to the TaxonomyField.

WCF Data Services at NEBytes

Many thanks to everyone who came to Newcastle to see my talk on WCF Data Services, managed to get through all my demos by overrunning a little bit! I’d also like to thank Ben, Jonathon and Damien for their hospitality and help. NEBytes is great user group and I’d recommend anyone who can attend to do so.

During the talk I was asked if WCF Data Services could be self hosted, which I didn’t think was possible. Turns out that it is possible and I would like to thank Steve Hobbs (who asked the question!) for emailing me (the same night!) and letting me know. Steve has posted sample code here and the MSDN reference to hosting Data Services is here.

The system cannot find the file specified. (2147942402, 80070002)

After updating the TFS 2010 client from Beta2 to RC on my SharePoint development machine I found that I couldn’t control IIS using IISRESET, with a message usually of the following format…

Attempting stop…

Stop attempt failed.

The system cannot find the file specified. (214794202, 80070002)

As anyone who does SharePoint development knows, not being able to restart IIS periodically is a bit of a annoyance and I didn’t want to keep going into IIS Manager to do this.

Turns out this is a problem with uninstalling Microsoft .NET 4.0 Beta 2 and the solution is to repair the Microsoft .NET Framework 4 Client Profile.

Windows Azure - Compute Hours Equals Deployed Hours

I signed up for the Windows Azure Platform Introductory Special. You get 25 hours of a small compute instance per month which is more than enough for my current development needs. I checked the billing after a couple of days and was surprised to see that I had used 4 hours of compute time. I'd only deployed a test application and loaded some test data. The compute instance had also been suspended for some of that time as well.

The little light in my head switched on.... COMPUTE HOURS equals DEPLOYED HOURS, suspended or otherwise. The only way to stop the clock ticking is to delete your application.

I still think 25 hours per month is good enough for my needs and the Windows Azure Platform Introductory Special is a great way to get used to Windows Azure as a commercial platform - just watch those hours.

comexception (0x80004005): cannot complete this action when deploying a SharePoint MasterPage as a feature

I've been working on deploying SharePoint MasterPages and PageLayouts as a feature. There are a lot of good posts out there on how to do this. Everything went ok, the feature deployed and activated fine, the page was approved and I could specify the masterpage to be used. I checked to see how the site looked and all was not well. The page blew and I had a nice comexception error:

    comexception (0x80004005): cannot complete this action

The strange thing is that the masterpage worked fine when manually uploaded to the masterpage gallery and only blew up when deployed as a feature. When searching the internet for comexception (0x80004005): cannot complete this action (what else do you do with COM exceptions and SharePoint?) I found information relating to identity impersonate, none of which was relevant the issue I was having.

I checked the application event logs and could see an ASP.NET 2.0.50727.0 warning message, with the event message "A parser error has occurred". Reading a bit further on into the event log entry I noticed "The type or namespace 'portal' does not exist in the namespace 'Microsoft.SharePoint' (are you missing an assembly reference?)". I checked the masterpage markup and noticed that a namespace was "Microsoft.SharePoint.portal.WebControls" when it should have been "Microsoft.SharePoint.Portal.WebControls".

In the end it was correcting a typo and paying good attention to what the event logs told me that saved the day.