Fair warning: The setup for this question is long, so be patient and stay with me.
I have two features in my solution package. The first is a set of site fields and content types; let's call this one Feature A. Among the fields are a field of type "TaxonomyFieldType" and an associate field of type "Note" (an explanation of the note field).
<Elements ...>
<Field ID="{956a1078-ec35-4c04-83c4-0a3742119496}"
Name="TaxonomyTextField"
Type="Note" DisplayName="Tags_0"
ShowInViewForms="FALSE"
Required="FALSE"
Group="MyGroup"
Hidden="TRUE"/>
<Field ID="{92BC866B-0415-45F0-B431-D4DF69C421CC}"
Name="Tags"
DisplayName="Custom Tags"
Type="TaxonomyFieldType"
ShowField="Term1033"
Required="FALSE"
Group="MyGroup"
>
<Customization>
<ArrayOfProperty>
<Property>
<Name>IsPathRendered</Name>
<Value xmlns:q7="http://www.w3.org/2001/XMLSchema" p4:type="q7:boolean" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">true</Value>
</Property>
<Property>
<Name>TextField</Name>
<Value xmlns:q6="http://www.w3.org/2001/XMLSchema" p4:type="q6:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">{956a1078-ec35-4c04-83c4-0a3742119496}</Value>
</Property>
</ArrayOfProperty>
</Customization>
</Field>
</Elements>
and
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<!-- Parent ContentType: Item (0x01) -->
<ContentType ID="0x0100b61c774f4c0e4a89bf230cbb44cd4f75"
Name="MyContent"
Group="MyGroup"
Description="Description of My Content Type"
Inherits="FALSE"
Overwrite="TRUE"
Version="0">
<FieldRefs>
<FieldRef ID="{52578fc3-1f01-4f4d-b016-94ccbcf428cf}" DisplayName="Comments" Name="Comments" Required="FALSE"/>
<FieldRef ID="{956a1078-ec35-4c04-83c4-0a3742119496}" Name="TimeTrackerTaxonomyTextField"/>
<FieldRef ID="{92BC866B-0415-45F0-B431-D4DF69C421CC}" DisplayName="Tags" Name="Tags" Required="FALSE"/>
</FieldRefs>
</ContentType>
</Elements>
In the feature receiver for the first feature (let's call it the Feature A), I programmatically retrieve this TaxonomyField
and
ensure that it is configured to retrieve terms out of a predetermined term set:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWeb web = GetWebObj(properties.Feature.Parent);
Guid fieldId = new Guid("92BC866B-0415-45F0-B431-D4DF69C421CC");
TaxonomyField field = web.Fields[fieldId] as TaxonomyField;
string groupName = properties.Feature.Properties["TaxonomyGroupName"].Value;
string termSetName = properties.Feature.Properties["TermSetName"].Value;
DiagnosticService logger = DiagnosticService.Local;
TermSet set = null;
TaxonomySession session = new TaxonomySession(web.Site);
TermSetCollection termSets = session.GetTermSets(termSetName, System.Threading.Thread.CurrentThread.CurrentUICulture.LCID);
if (termSets == null || termSets.Count == 0)
{
logger.WriteTrace(1, logger[CategoryId.Deployment], TraceSeverity.Medium,
"Activity Tags term set not found. Ensuring '{0}' group and '{1}' term set.", groupName, termSetName);
// create the term set in the default store
var store = session.DefaultSiteCollectionTermStore;
var group = store.EnsureGroup(groupName);
set = group.EnsureTermSet(termSetName);
store.CommitAll();
logger.WriteTrace(1, logger[CategoryId.Provisioning], TraceSeverity.Verbose, "created taxonomy group '{0}' and term set '{1}'", group, set);
}
else
{
logger.WriteTrace(1, logger[CategoryId.Deployment], TraceSeverity.Verbose, "term set found.");
// need to make sure we grab the one in the right group, or it might be someone else's term set.
foreach (var termSet in termSets)
{
if (String.Equals(termSet.Group.Name,groupName))
{
if (set == null)
{
set = termSet;
}
else
{
logger.WriteTrace(1, logger[CategoryId.Deployment], TraceSeverity.Unexpected,
"Multiple term sets named '{0}' found in more than one taxonomy group.", termSetName);
throw new SPException(String.Format("Multiple term sets named '{0}' found in more than one taxonomy group. "+
"Was there a previous installation that was not removed properly?", termSetName));
}
}
}
if (set == null)
{
// term set found, but in an unrecognized group. leave it alone and do like above
logger.WriteTrace(1, logger[CategoryId.Deployment], TraceSeverity.Verbose,
"Term set '{0}' found, but in unrecognized group. Provisioning new group and term set as configured.", termSetName);
var store = session.DefaultSiteCollectionTermStore;
var group = store.EnsureGroup(groupName);
set = group.EnsureTermSet(termSetName);
store.CommitAll();
logger.WriteTrace(1, logger[CategoryId.Provisioning], TraceSeverity.Verbose, "created taxonomy group '{0}' and term set '{1}'", group, set);
}
}
// set termSets to the newly created term set
field.SspId = set.TermStore.Id;
field.TermSetId = set.Id;
field.TargetTemplate = String.Empty;
field.AnchorId = Guid.Empty;
field.Open = true;
field.AllowMultipleValues = true;
field.Update();
}
The second feature contains list templates and instances, one of which uses the above content type; let's call this feature Feature B.
Here's the list schema for the list that blows up when provisioned (ListInstance
element not shown):
<?xml version="1.0" encoding="utf-8"?>
<List xmlns:ows="Microsoft SharePoint" Title="My List" FolderCreation="FALSE" Direction="$Resources:Direction;" Url="Lists/MyList" BaseType="0" xmlns="http://schemas.microsoft.com/sharepoint/">
<MetaData>
<ContentTypes>
<ContentTypeRef ID="0x0100b61c774f4c0e4a89bf230cbb44cd4f75"></ContentTypeRef>
</ContentTypes>
<Fields>
<Field ID="{956a1078-ec35-4c04-83c4-0a3742119496}" Name="TaxonomyTextField" Type="Note"/>
<Field ID="{92bc866b-0415-45f0-b431-d4df69c421cc}" Name="Tags" Type="TaxonomyFieldType"/>
<Field ID="{52578FC3-1F01-4f4d-B016-94CCBCF428CF}" Name="_Comments" Type="Note"/>
</Fields>
<Views>
<View BaseViewID="1" Type="HTML" WebPartZoneID="Main" DisplayName="$Resources:core,objectiv_schema_mwsidcamlidC24;" DefaultView="TRUE" MobileView="TRUE" MobileDefaultView="TRUE" SetupPath="pages\viewpage.aspx" ImageUrl="/_layouts/images/generic.png" Url="AllItems.aspx">
<Toolbar Type="Standard" />
<XslLink Default="TRUE">main.xsl</XslLink>
<RowLimit Paged="TRUE">30</RowLimit>
<ViewFields>
<!-- <FieldRef Name="Tags"></FieldRef> -->
<FieldRef Name="_Comments"></FieldRef>
</ViewFields>
<Query>
<OrderBy>
<FieldRef Name="ID">
</FieldRef>
</OrderBy>
</Query>
<ParameterBindings>
<ParameterBinding Name="NoAnnouncements" Location="Resource(wss,noXinviewofY_LIST)" />
<ParameterBinding Name="NoAnnouncementsHowTo" Location="Resource(wss,noXinviewofY_DEFAULT)" />
</ParameterBindings>
</View>
</Views>
<Forms>
<Form Type="DisplayForm" Url="DispForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="EditForm" Url="EditForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
</Forms>
</MetaData>
</List>
After the solution deploys, I am able to activate Feature A without issue. The site columns and content types are created. When I attempt to activate Feature B, the feature activation call stack blows up and results in an error page with the following stack trace:
[COMException (0x80004005): Cannot complete this action. Please try again.] Microsoft.SharePoint.Library.SPRequestInternalClass.UpdateField(String bstrUrl, String bstrListName, String bstrXML) +0 Microsoft.SharePoint.Library.SPRequest.UpdateField(String bstrUrl, String bstrListName, String bstrXML) +134 [SPException: Cannot complete this action. Please try again.] Microsoft.SharePoint.Administration.SPElementDefinitionCollection.ProvisionListInstances(SPFeaturePropertyCollection props, SPSite site, SPWeb web, Boolean fForce) +23649702 Microsoft.SharePoint.Administration.SPElementDefinitionCollection.ProvisionElements(SPFeaturePropertyCollection props, SPWebApplication webapp, SPSite site, SPWeb web, Boolean fForce) +197 Microsoft.SharePoint.SPFeature.Activate(SPSite siteParent, SPWeb webParent, SPFeaturePropertyCollection props, Boolean fForce) +25437263 Microsoft.SharePoint.SPFeatureCollection.AddInternal(SPFeatureDefinition featdef, Version version, SPFeaturePropertyCollection properties, Boolean force, Boolean fMarkOnly) +27496735 Microsoft.SharePoint.SPFeatureCollection.AddInternalWithName(Guid featureId, String featureName, Version version, SPFeaturePropertyCollection properties, Boolean force, Boolean fMarkOnly, SPFeatureDefinitionScope featdefScope) +150 Microsoft.SharePoint.SPFeatureCollection.Add(Guid featureId, Boolean force, SPFeatureDefinitionScope featdefScope) +83 Microsoft.SharePoint.WebControls.FeatureActivator.ActivateFeature(Guid featid, SPFeatureDefinitionScope featdefScope) +699 Microsoft.SharePoint.WebControls.FeatureActivatorItem.BtnActivateFeature_Click(Object objSender, EventArgs evtargs) +140 System.Web.UI.WebControls.Button.OnClick(EventArgs e) +115 System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +140 System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +29 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2981
I'm fairly certain that there's something wrong with the way I'm configuring the TaxonomyField
in Feature A; its association with a list instance at provisioning time is the cause of the error (I've determined this by commenting out pieces and deploying over and over). There seems to be very little documentation, or even blogger experience, with TaxonomyFields
and provisioning them in list instances, so I'm a bit at a loss. Does someone have any idea what's going wrong?
I followed How to provision SharePoint 2010 Managed Metadata columns by Wictor Wilén and was able to get something similar working (be sure to also make the modification from this comment).