Quantcast
Channel: Mavention
Viewing all articles
Browse latest Browse all 627

Inconvenient list content type inheritance using CSOM

$
0
0

Adding new content types is easy in CSOM using the new ContentTypeCreationInformation class. This class does pretty much all the heavy lifting for you as Vesa describes in one of the blogs in the FTC to CAM series (http://blogs.msdn.com/b/vesku/archive/2014/02/28/ftc-to-cam-create-content-types-with-specific-ids-using-csom.aspx).
This mechanism works fine for site content types, but when you try using this to provision a content type to a list something strange happens. The content type seems to inherit from its site content type parent, but all the fields from the parent are missing. To test this in an isolated environment, I created a provider-hosted app with this snippet:

 protected void Page_Load(object sender, EventArgs e)
        {
            // The following code gets the client context and Title property by using TokenHelper.
            // To access other properties, the app may need to request permissions on the host web.
            var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);

            using (var clientContext = spContext.CreateUserClientContextForSPHost())
            {
                // load web and list
                clientContext.Load(clientContext.Web);
                clientContext.ExecuteQuery();

                var list = clientContext.Web.GetList("/sites/dev-en/SitePages");
                clientContext.Load(list);
                clientContext.ExecuteQuery();

                // content type id of Image 
                var parentContentTypeId = "0x0101009148F5A04DDD49CBA7127AADA5FB792B00AADE34325A8B49CDA8BB4DB53328F214";
                EnsureContentTypeFields(clientContext, list, parentContentTypeId);

                var info = new ContentTypeCreationInformation
                {
                    // set up new content type inheriting from Image
                    Id = parentContentTypeId + "00" + "9F13E4D76C8843D6BAF5EACD8EE880AB",
                    Name = "MyNewContentType",
                };

                // add new content type to the list
                list.ContentTypes.Add(info);
                clientContext.ExecuteQuery();
            }
        }

The result is as follows. Note that the fields from parent content type (Image) are missing in the new content type.

Missing columns in list content type 

Debugging this on my local farm, I discovered that the fields are actually added to the list content type as expected. The problem is not that the content type is inherited incorrectly, but that fields are not pushed to the list. Since the fields are not present in the list, SharePoint hides them in the content type as well. The solution is to manually push the fields to the list prior to provisioning the content type.

 protected void Page_Load(object sender, EventArgs e)
        {
            // The following code gets the client context and Title property by using TokenHelper.
            // To access other properties, the app may need to request permissions on the host web.
            var spContext = SharePointContextProvider.Current.GetSharePointContext(Context);

            using (var clientContext = spContext.CreateUserClientContextForSPHost())
            {
                // load web and list
                clientContext.Load(clientContext.Web);
                clientContext.ExecuteQuery();

                var list = clientContext.Web.GetList("/sites/dev-en/SitePages");
                clientContext.Load(list);
                clientContext.ExecuteQuery();

                // content type id of Image 
                var parentContentTypeId = "0x0101009148F5A04DDD49CBA7127AADA5FB792B00AADE34325A8B49CDA8BB4DB53328F214";
                EnsureContentTypeFields(clientContext, list, parentContentTypeId);

                var info = new ContentTypeCreationInformation
                {
                    // set up new content type inheriting from Image
                    Id = parentContentTypeId + "00" + "9F13E4D76C8843D6BAF5EACD8EE880AB",
                    Name = "MyNewContentType",
                };

                // add new content type to the list
                list.ContentTypes.Add(info);
                clientContext.ExecuteQuery();
            }
        }

        protected void EnsureContentTypeFields(ClientContext context, List list, string contentTypeId)
        {
            // get the content type
            context.Load(list.ParentWeb.AvailableContentTypes);
            context.ExecuteQuery();

            var contentType = list.ParentWeb.AvailableContentTypes.FirstOrDefault(c => c.Id.ToString() == contentTypeId);
            if (contentType == null)
            {
                throw new InvalidOperationException("Content type not found");
            }

            // load the fields in the list and the fields in the content type
            var currentFields = list.Fields;
            var requiredFields = contentType.Fields;
            context.Load(currentFields);
            context.Load(requiredFields);
            context.ExecuteQuery();

            foreach (var field in requiredFields)
            {
                var currentField = currentFields.FirstOrDefault(f => f.Id == field.Id);
                if (currentField == null)
                {
                    // add the field
                    currentFields.Add(field);
                    context.ExecuteQuery();

                    // update the local collection
                    context.Load(currentFields);
                    context.ExecuteQuery();
                }
            }
        }

As a result, the fields are added to the list and available in the content type.

List content type fields added to list 

Complete list content type  


Viewing all articles
Browse latest Browse all 627

Trending Articles