Removing a Site Column from a Content Type using the Client Object Model

I don’t know how many hours I have spent trying to remove a site column using CSOM. There is a specifc way to do so and you have to do it in the right order. Below is how you would remove a site column that has been provisioned to a SharePoint site, is associated with a Content Type, and is also added to a list.

First you need to get a reference of the field:

ClientContext cc = new ClientContext(siteUrl);
cc.AuthenticationMode = ClientAuthenticationMode.Default;
cc.Credentials = new SharePointOnlineCredentials(userName, pwd);
Web web = cc.Web;

Field field = web.Fields.GetByInternalNameOrTitle(fieldName);

Next, you need to use the FieldLink object to remove the site column from the content type:

ContentType cType = web.GetContentTypeByName(cTypeName);
FieldLink cTypeField = cType.FieldLinks.GetById(field.Id);

It is critical to call an Update() on the content type before executing your query.

The next step is to remove the site column from your list as it will be orphaned if you don’t.

List list = web.Lists.GetByTitle(listName);

if (list.FieldExistsByName(fieldName))

Finally, remove the site column itself:




Registering Custom Event Handlers

If you are looking for a quick way to manage event handlers in SharePoint 2007, please check out my solution at CodePlex and download a WSP package that will allow you to do this using STSADM.

There are many ways to register event handlers and you can certainly pick your flavor. However, please feel free to use this solution I wrote a few years ago (but only recently published to CodePlex).

You can do the following with this solution:

  1. Add event handlers
  2. List registered event handlers
  3. Delete event handlers

All this from the command line ease of STSADM.

Also, please stay tuned as I re-work this solution as PowerShell extensions for SharePoint 2010 in the near future.

Provisioning SharePoint Lookup Columns

There is alot of misinformation out there in the blogosphere regarding SharePoint Lookup Columns and how to provision them correctly with a Feature.

Let me just say that I’ve tried about every technique I have found, including declaritvely defining the lookup column through CAML schema (field and list definition).  Every technique I have tried (declaritvely) doesn’t work. MSDN references that the <Field> tag can have a List property and that it is the “internal name” of the list. Others say it’s the GUID of the list, while others say it has to all be done in the list schema.

So…as a result, let me give you my two cents on the subject. DON’T declaritvely try to provision a Lookup field. It’s more of a headache than its really worth. In my opinion, the best practice is to do it through a Feature Receiver. You will have complete control over how the lookup field will get created and used. Besides, using a list GUID through XML schema is nonsense, unless you are creating a ListInstance with that GUID (but I’ve tried that too and it doesn’t work).

Go the Feature Receiver route, trust me. There are a few posts out there on various blogs, including a downloadable example on CodePlex. They are all great and will work. However, if you don’t want to bother with those…let me just provide you my technique on provisioning a Lookup column.

First, define a feature that will call a custom Feature Receiver like the following:

<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns=
	Title="Base Feature"
	Description="Provisions base content types and fields for the site."
	ReceiverAssembly="TSC.SharePoint, Version=, Culture=neutral, PublicKeyToken=f1710125c5a87ae6"
	ImageUrlAltText="TSC Custom Feature">
		<ElementManifest Location="tscfields.xml"/>
		<ElementManifest Location="tscctypes.xml"/>

Next, create a class in Visual Studio that will inherit SPFeatureReceiver like the following:

public class TSCBaseFeatureReceiver : SPFeatureReceiver
    public override void FeatureActivated(SPFeatureReceiverProperties properties)
        using (SPSite site = (SPSite)properties.Feature.Parent)
              using (SPWeb web = site.RootWeb)
                 // Set lookup columns.
                 SPFieldLookup lookupCol = ProvisionLookupField("MyFieldTitle", "My Field Display Name", "My Site Columns", true, true, SPContext.Current.Site.RootWeb, SPContext.Current.Site.RootWeb.Lists["My List Title"], "Title");
                 LinkToCType(SPContext.Current.Site.RootWeb, "My Content Type", (SPField)lookupCol);

    public override void FeatureDeactivating(SPFeatureReceiverProperties properties)

    public override void FeatureInstalled(SPFeatureReceiverProperties properties)

    public override void FeatureUninstalling(SPFeatureReceiverProperties properties)

The last step is to create the methods the code above calls. You can place these methods in the same Feature Receiver below the “FeatureUninstalling” method.

It is important to have your feature first create the lookup column, then to associate the column to a content type. If you look at my Feature XML, you will see that I have an ElementManifest to provision a “tscctypes.xml” file. Within this file, I have defined a few custom content types. You can follow the same process, just change “My Content Type” to the name of the content type you are defining in your Feature.

Now, here are the remaining pieces of code to get this to work:

public static SPFieldLookup ProvisionLookupField(string fieldName, string fieldDisplayName, string group, bool required, bool allowMultipleValues, SPWeb web, SPList lookupList, string lookupField)
    web.Fields.AddLookup(fieldName, lookupList.ID, lookupList.ParentWeb.ID, required);
    SPFieldLookup lookup = (SPFieldLookup)web.Fields.GetFieldByInternalName(fieldName);
    lookup.AllowMultipleValues = allowMultipleValues;
    lookup.LookupField = lookupField;
    lookup.Title = fieldDisplayName;
    lookup.Group = group;
    return lookup;

public static void LinkToCType(SPWeb web, string contentType, SPField field)
    SPContentType ct = web.ContentTypes[contentType];
    ct.FieldLinks.Add(new SPFieldLink(field));

That’s it!