I’ve been working on a SharePoint provider hosted app for a client and part of the overall solution is a deployment of artifacts to the Host web.  There are many valid and important reasons for having your app use the host web as its main data store opposed to the app web.  In short, if your app is considered the center piece of your site and is used to accomplish things you would have typically tried to do using full trust code in the past, the host web is probably your best bet.  If your app is a widget and you expect to install it in many sites then the app web is how you should probably go.  Just my 2 cents, probably worthy of another post to join the fray of opinions.  Just remember, if your app gets uninstalled, everything in the app web goes along with it.

Back to the issue, I’ll try to keep it short and sweet.  I opted to create a console application to do the deployment to the host web.  At some point in SharePoint development you usually run into the scenario where you either delete the site collection or just delete some lists, content types, etc. and try to re-deploy for testing.

After deleting some of my custom site columns of type “TaxonomyFieldType” and “TaxonomyFieldTypeMulti”, I tried to run my deployment project and ran into this issue.

When you create a Taxonomy field, SharePoint actually creates 2 fields.  The first is the field that you created.  The second is a hidden, cryptically named, “helper” field.  When you delete a taxonomy field the hidden field is left behind.

The naming logic goes like this.  Take the id of the Taxonomy field, convert to lower case, remove all hyphens, then replace the first character with another character.  I’m not sure how the first character is derived, I just know it replaces the original first character

So, for example...  {787F977C-EA60-47F0-88B8-B7651J21CECE} becomes l87f977cea6047f088b8b7651j21cece, and l87f977cea6047f088b8b7651j21cece is the name of the hidden field.  So in order to truly delete a taxonomy field I wrote the following code to delete both fields.  You could also attempt to create the field, catch the exception, extract the hidden field name from the exception message, delete the field again, then use the extracted hidden field name to delete the hidden field.

public static void DeleteField(ClientContext cc, string internalName,string id = "")
{
    FieldCollection fields = cc.Web.Fields;
    cc.Web.Context.Load(fields, fc => fc.Include(f => f.Id, f => f.InternalName));
    cc.Web.Context.ExecuteQuery();

    var field = fields.FirstOrDefault(f => f.InternalName == internalName);

    if (field != null)
    {
        id = field.Id.ToString();
       
field.DeleteObject();
       
cc.Web.Context.ExecuteQuery();
    
}

    if (id != string.Empty)
   
{
       
string hiddenFieldName = id.ToLower().Replace("-", string.Empty).Replace("{", string.Empty).Replace("}", string.Empty).Substring(1);
       
field = fields.FirstOrDefault(f => f.InternalName.EndsWith(hiddenFieldName));
        
if (field != null)
       
{
           
field.DeleteObject();
            
cc.Web.Context.ExecuteQuery();
       
}

     }

    
cc.Web.Update();

}