0

I'm using the REST API to add items to a list that has a managed metadata field (single valued, no items localization, all items have unique labels).

The problem is that the code only knows the Label of the term value to set, the corresponding GUID is unknown. I can set the managed metadata field value, but I need to know both the label AND the GUID of the term to set.

I'm neither in a webapp nor in a Sharepoint app, so I can't use JSOM - OData/XML APIs only (I'm actually porting code that currently uses CSOM to OData in order to migrate the application to .net standard). Unfortunately, we're still on SharePoint 2013.

How do I retrieve the term GUID from the label?

1 Answer 1

0

It took a while, but in the end it turns out it can be done. Here I'm using Simple OData Client and a Service Reference to https://<host>/_vti_bin/TaxonomyClientService.asmx called WsSpTaxonomyService:

public Guid? GetTermGuid(string siteUrl, string userName, string password, string domain,
  string listName, string fieldInternalName, string termLabel)
{
  // Retrieve SspId and TermSetId
  GetManagedMetadataFieldDetails(siteUrl, userName, password, domain, listName, fieldInternalName, out var sspId, out var termSetId);

  // Now that we have SspId and TermSetId, we can invoke the SOAP service to obtain the item GUID
  var termGuid = GetTermInfoWS(siteUrl, userName, password, domain, termLabel, sspId, termSetId);
  return termGuid;
}
    
private static void GetManagedMetadataFieldDetails(string siteUrl, string userName, string password, string domain,
  string listName, string fieldInternalName, out Guid sspId, out Guid termSetId)
{
  // These attributes could be retrieved using REST with a single call to https://<host>/_api/Lists/getbytitle('<list name>')/fields/getbytitle('<field>')?$select=SspId,TermSetId
  // Unfortunately Simple OData Client does not support this invocation, we need to split it into two separate calls

  var spSiteUrl = !siteUrl.EndsWith("/") ? siteUrl + "/" : siteUrl;

  var settings = new ODataClientSettings(new Uri(new Uri(spSiteUrl), "_api/"));
  settings.Credentials = new NetworkCredential(userName, password, domain);
  settings.PayloadFormat = ODataPayloadFormat.Json; // Request JSON Light

  // SP does not accept the apostrophe encoding in function calls, force URL decoding
  settings.BeforeRequest += (requestMessage) => {
    string url = System.Web.HttpUtility.UrlDecode(requestMessage.RequestUri.AbsoluteUri);
    requestMessage.RequestUri = new Uri(url);
  };

  var client = new ODataClient(settings);

  // 1. Retrieve list GUID
  // https://<host>/_api/Lists/getbytitle('<list name>') 
  var listEntity = client
    .For("Lists")
    .Function("getByTitle")
    .Set(new { title = listName })
    .FindEntryAsync()
    .Result;

  var listGuid = (Guid)listEntity["Id"];

  // 2. Retrieve field details
  // https://<host>/_api/Lists(guid'<guid>')/Fields?$filter=InternalName eq '<field>'
  var fieldsEntity = client
    .For("Lists")
    .Key(listGuid)
    .NavigateTo("Fields")
    .Filter("InternalName eq '" + fieldInternalName + "'")
    .FindEntryAsync()
    .Result;

  sspId = (Guid)fieldsEntity["SspId"];
  termSetId = (Guid)fieldsEntity["TermSetId"];
}

private static Guid? GetTermInfoWS(string siteUrl, string userName, string password, string domain,
  string termLabel, Guid sspId, Guid termSetId)
{
  var spSiteUrl = !siteUrl.EndsWith("/") ? siteUrl + "/" : siteUrl;
  var serviceUrl = new Uri(new Uri(spSiteUrl), "_vti_bin/TaxonomyClientService.asmx").AbsoluteUri;

  WsSpTaxonomyService service = new WsSpTaxonomyService();
  service.ClientCredentials.Windows.ClientCredential.UserName = userName;
  service.ClientCredentials.Windows.ClientCredential.Password = password;
  service.ClientCredentials.Windows.ClientCredential.Domain = domain;

  var sXml = service.GetTermsByLabel(termLabel, CultureInfo.GetCultureInfo("en-US").LCID, StringMatchOption.ExactMatch, 1000,
  string.Format("<termSetId>{0}</termSetId>", termSetId.ToString("D")), false);

  XElement schemaRoot = XElement.Parse(sXml);
  var objTerm = schemaRoot.Descendants("T").SingleOrDefault(
    e => e.Element("LS").Element("TL").Attribute("a32").Value.Equals(termLabel));
  Guid? termGuid = objTerm != null ? new Guid(objTerm.Attribute("a9").Value) : (Guid?)null;

  return termGuid;
}

Please note that this code assumes that the service reference points to the correct site URL and that locale for the term label is US English. It can be easily generalized further, but I really need a drink now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.