none
How can you publish a content type from CSOM on SharePoint Online

    Question

  • Hello,

    Is it possible to publish a content type created in the Content Type hub of a SharePoint Online Tenant?

    I know doing this On-Premise requires this: Microsoft.SharePoint.Taxonomy.ContentTypeSync.ContentTypePublisher

    But I can not find any SharePoint Online Client equivalent.

    Any help on this issue would be greatly appreciated.

    Thank you,

    Brad Garner


    Brad

    Wednesday, October 12, 2016 3:27 PM

Answers

  • Hello AmitVasu,

    Thank you for your prompt response. I looked into your suggested workaround and didn't find it satisfactory enough as I was looking for a CSOM option for a tool we are building.  So here is what I came up with...loosely based off two different things I found online.

    CSOM WebRequests Example:

    Adding a new version in version collection of Document set using SharePoint 2013 CSOM & JSOM

    Powershell WebRequests Example:

    PublishContentTypesO365.ps1

    All props to these guys on their work.

    And here is my working result to publish content types in C# with CSOM on SharePoint Online (not tested On-Prem):

                string ctId = "0x0000000000000000000000000000000000";
    	    bool publishCt = true;
                string buttonToClick = "publishButton";
                if (!publishCt)
                {
                    buttonToClick = "unpublishButton";
                }
    			
    			context.Load(site, s => s.Url);
                context.ExecuteQuery();
    
                string ctPubPageUrl = site.Url + "/_layouts/15/managectpublishing.aspx?ctype=" + ctId;
    
                // create Web Request using client context
                HttpWebRequest request = context.WebRequestExecutorFactory.CreateWebRequestExecutor(context, ctPubPageUrl).WebRequest;
    
                request.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
                request.Accept = "application/json;odata=verbose";
                request.Method = WebRequestMethods.Http.Get;
                request.ContentLength = 0;
    
                if (context.Credentials != null)
                {
                    //Use Context Credentials
                    request.Credentials = context.Credentials;
                }
                else
                {
                    // No specific authentication required
                    request.UseDefaultCredentials = true;
                }
    
                WebResponse response = request.GetResponse();
    
                // decode response
                string strResponse;
                Stream stream = response.GetResponseStream();
                if (!string.IsNullOrEmpty(response.Headers["Content-Encoding"]))
                {
                    if (response.Headers["Content-Encoding"].ToLower().Contains("gzip"))
                    {
                        stream = new System.IO.Compression.GZipStream(stream, System.IO.Compression.CompressionMode.Decompress);
                    }
                    else if (response.Headers["Content-Encoding"].ToLower().Contains("deflate"))
                    {
                        stream = new System.IO.Compression.DeflateStream(stream, System.IO.Compression.CompressionMode.Decompress);
                    }
                }
    
                // get response string
                StreamReader sr = new StreamReader(stream);
                strResponse = sr.ReadToEnd();
                sr.Close();
                sr.Dispose();
                stream.Close();
    
                // Look for inputs and add them to the dictionary for postback values
                var inputs = new List<KeyValuePair<string, string>>();
    
                string patInput = @"<input.+?\/??>";
                string patName = @"name=\""(.+?)\""";
                string patValue = @"value=\""(.+?)\""";
                string patDisabled = @"disabled=\""(.+?)\""";
    
                // Instantiate the regular expression object.
                Regex r = new Regex(patInput, RegexOptions.IgnoreCase);
                Regex rName = new Regex(patName, RegexOptions.IgnoreCase);
                Regex rValue = new Regex(patValue, RegexOptions.IgnoreCase);
                Regex rDisabled = new Regex(patDisabled, RegexOptions.IgnoreCase);
    
                // Match the regular expression pattern against a text string.
                Match m = r.Match(strResponse);
                while (m.Success)
                {
                    string name = string.Empty;
                    string value = string.Empty;
                    bool disabled = false;
    
                    if (rName.IsMatch(m.Value))
                    {
                        //Example: name="ctl00$PlaceHolderMain$actionSection$RadioGroupAction"
                        name = rName.Match(m.Value).Groups[1].Value;
                    }
    
                    if (rValue.IsMatch(m.Value))
                    {
                        //Example: value="publishButton"
                        value = rValue.Match(m.Value).Groups[1].Value;
                    }
    
                    if (rDisabled.IsMatch(m.Value))
                    {
                        //Example: disabled="disabled"
                        disabled = true;
                    }
    
                    //didn't find what we were looking for...go to the next match...
                    if (string.IsNullOrEmpty(name))
                    {
                        m = m.NextMatch();
                        continue;
                    }
    
                    //if it's the operation radio button group and it matches the action
                    if (name == "ctl00$PlaceHolderMain$actionSection$RadioGroupAction" && buttonToClick == value)
                    {
                        if (disabled == true)
                        {
                            if (publishCt)
                            {
                                //requested publish, it's already published so we'll just republish it
                                inputs.Add(new KeyValuePair<string, string>(name, "republishButton"));
                            }
                        }
                        //operation requested is valid based on current state
                        else
                        {
                            inputs.Add(new KeyValuePair<string, string>(name, value));
                        }
                    }
                    else if (name == "ctl00$PlaceHolderMain$actionSection$RadioGroupAction" && buttonToClick != value)
                    {
                        //This is not the radio button you are looking for...move along...
                    }
                    //operation requested is valid based on current state
                    else if (name != "" && value != "")
                    {
                        //Add all the other inputs that have a name and value
                        inputs.Add(new KeyValuePair<string, string>(name, value));
                    }
    
                    m = m.NextMatch();
                }
    
                string strPost = "";
    
                var sortedinputs = inputs.OrderBy(n => n.Key); //This is neccesary otherwise the post does nothing...
    
                foreach (var i in sortedinputs)
                {
                    if (!String.IsNullOrEmpty(i.Key) && !i.Key.EndsWith("iidIOGoBack"))
                    {
                        strPost += Uri.EscapeDataString(i.Key) + "=" + Uri.EscapeDataString(i.Value) + "&";
                    }
                }
                strPost = strPost.TrimEnd('&');
    
                var postData = Encoding.UTF8.GetBytes(strPost);
    
                //Build postback request
                HttpWebRequest publishrequest = context.WebRequestExecutorFactory.CreateWebRequestExecutor(context, ctPubPageUrl).WebRequest;
                publishrequest.Method = "POST";
                publishrequest.Accept = "text/html, application/xhtml+xml, */*";
                publishrequest.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
                publishrequest.ContentType = "application/x-www-form-urlencoded";
                publishrequest.ContentLength = postData.Length;
                publishrequest.Headers["Cache-Control"] = "no-cache";
                publishrequest.Headers["Accept-Encoding"] = "gzip, deflate";
                publishrequest.Headers["Accept-Language"] = "fr-FR,en-US";
    
                if (context.Credentials != null)
                {
                    //Use Context Credentials
                    publishrequest.Credentials = context.Credentials;
                }
                else
                {
                    // No specific authentication required
                    publishrequest.UseDefaultCredentials = true;
                }
    
                //Add postback data to the request stream
                stream = publishrequest.GetRequestStream();
                stream.Write(postData, 0, postData.Length);
                stream.Close();
                stream.Dispose();
    
                //Perform the postback
                HttpWebResponse publishResponse = (HttpWebResponse) publishrequest.GetResponse();
    
                //Make sure the response is OK and that it was redirected to the right page
                if (publishResponse.StatusCode != HttpStatusCode.OK || publishResponse.ResponseUri.AbsolutePath != "/sites/contentTypeHub/_layouts/15/ManageContentType.aspx")
                {
                    //Log Something went wrong...
                }
    
                publishResponse.Close();
                publishResponse.Dispose();


    Brad

    • Marked as answer by bgarner Tuesday, October 18, 2016 12:56 PM
    Tuesday, October 18, 2016 12:56 PM

All replies

  • Wednesday, October 12, 2016 3:38 PM
    Moderator
  • Hi,

    Is any update for your issue? You could mark the replies an answers if the replies helped you.

    Best Regards,

    Lee


    Please remember to mark the replies as an answers if they help and unmark them if they provide no help.
    If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com

    Monday, October 17, 2016 6:36 AM
  • Hello AmitVasu,

    Thank you for your prompt response. I looked into your suggested workaround and didn't find it satisfactory enough as I was looking for a CSOM option for a tool we are building.  So here is what I came up with...loosely based off two different things I found online.

    CSOM WebRequests Example:

    Adding a new version in version collection of Document set using SharePoint 2013 CSOM & JSOM

    Powershell WebRequests Example:

    PublishContentTypesO365.ps1

    All props to these guys on their work.

    And here is my working result to publish content types in C# with CSOM on SharePoint Online (not tested On-Prem):

                string ctId = "0x0000000000000000000000000000000000";
    	    bool publishCt = true;
                string buttonToClick = "publishButton";
                if (!publishCt)
                {
                    buttonToClick = "unpublishButton";
                }
    			
    			context.Load(site, s => s.Url);
                context.ExecuteQuery();
    
                string ctPubPageUrl = site.Url + "/_layouts/15/managectpublishing.aspx?ctype=" + ctId;
    
                // create Web Request using client context
                HttpWebRequest request = context.WebRequestExecutorFactory.CreateWebRequestExecutor(context, ctPubPageUrl).WebRequest;
    
                request.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
                request.Accept = "application/json;odata=verbose";
                request.Method = WebRequestMethods.Http.Get;
                request.ContentLength = 0;
    
                if (context.Credentials != null)
                {
                    //Use Context Credentials
                    request.Credentials = context.Credentials;
                }
                else
                {
                    // No specific authentication required
                    request.UseDefaultCredentials = true;
                }
    
                WebResponse response = request.GetResponse();
    
                // decode response
                string strResponse;
                Stream stream = response.GetResponseStream();
                if (!string.IsNullOrEmpty(response.Headers["Content-Encoding"]))
                {
                    if (response.Headers["Content-Encoding"].ToLower().Contains("gzip"))
                    {
                        stream = new System.IO.Compression.GZipStream(stream, System.IO.Compression.CompressionMode.Decompress);
                    }
                    else if (response.Headers["Content-Encoding"].ToLower().Contains("deflate"))
                    {
                        stream = new System.IO.Compression.DeflateStream(stream, System.IO.Compression.CompressionMode.Decompress);
                    }
                }
    
                // get response string
                StreamReader sr = new StreamReader(stream);
                strResponse = sr.ReadToEnd();
                sr.Close();
                sr.Dispose();
                stream.Close();
    
                // Look for inputs and add them to the dictionary for postback values
                var inputs = new List<KeyValuePair<string, string>>();
    
                string patInput = @"<input.+?\/??>";
                string patName = @"name=\""(.+?)\""";
                string patValue = @"value=\""(.+?)\""";
                string patDisabled = @"disabled=\""(.+?)\""";
    
                // Instantiate the regular expression object.
                Regex r = new Regex(patInput, RegexOptions.IgnoreCase);
                Regex rName = new Regex(patName, RegexOptions.IgnoreCase);
                Regex rValue = new Regex(patValue, RegexOptions.IgnoreCase);
                Regex rDisabled = new Regex(patDisabled, RegexOptions.IgnoreCase);
    
                // Match the regular expression pattern against a text string.
                Match m = r.Match(strResponse);
                while (m.Success)
                {
                    string name = string.Empty;
                    string value = string.Empty;
                    bool disabled = false;
    
                    if (rName.IsMatch(m.Value))
                    {
                        //Example: name="ctl00$PlaceHolderMain$actionSection$RadioGroupAction"
                        name = rName.Match(m.Value).Groups[1].Value;
                    }
    
                    if (rValue.IsMatch(m.Value))
                    {
                        //Example: value="publishButton"
                        value = rValue.Match(m.Value).Groups[1].Value;
                    }
    
                    if (rDisabled.IsMatch(m.Value))
                    {
                        //Example: disabled="disabled"
                        disabled = true;
                    }
    
                    //didn't find what we were looking for...go to the next match...
                    if (string.IsNullOrEmpty(name))
                    {
                        m = m.NextMatch();
                        continue;
                    }
    
                    //if it's the operation radio button group and it matches the action
                    if (name == "ctl00$PlaceHolderMain$actionSection$RadioGroupAction" && buttonToClick == value)
                    {
                        if (disabled == true)
                        {
                            if (publishCt)
                            {
                                //requested publish, it's already published so we'll just republish it
                                inputs.Add(new KeyValuePair<string, string>(name, "republishButton"));
                            }
                        }
                        //operation requested is valid based on current state
                        else
                        {
                            inputs.Add(new KeyValuePair<string, string>(name, value));
                        }
                    }
                    else if (name == "ctl00$PlaceHolderMain$actionSection$RadioGroupAction" && buttonToClick != value)
                    {
                        //This is not the radio button you are looking for...move along...
                    }
                    //operation requested is valid based on current state
                    else if (name != "" && value != "")
                    {
                        //Add all the other inputs that have a name and value
                        inputs.Add(new KeyValuePair<string, string>(name, value));
                    }
    
                    m = m.NextMatch();
                }
    
                string strPost = "";
    
                var sortedinputs = inputs.OrderBy(n => n.Key); //This is neccesary otherwise the post does nothing...
    
                foreach (var i in sortedinputs)
                {
                    if (!String.IsNullOrEmpty(i.Key) && !i.Key.EndsWith("iidIOGoBack"))
                    {
                        strPost += Uri.EscapeDataString(i.Key) + "=" + Uri.EscapeDataString(i.Value) + "&";
                    }
                }
                strPost = strPost.TrimEnd('&');
    
                var postData = Encoding.UTF8.GetBytes(strPost);
    
                //Build postback request
                HttpWebRequest publishrequest = context.WebRequestExecutorFactory.CreateWebRequestExecutor(context, ctPubPageUrl).WebRequest;
                publishrequest.Method = "POST";
                publishrequest.Accept = "text/html, application/xhtml+xml, */*";
                publishrequest.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
                publishrequest.ContentType = "application/x-www-form-urlencoded";
                publishrequest.ContentLength = postData.Length;
                publishrequest.Headers["Cache-Control"] = "no-cache";
                publishrequest.Headers["Accept-Encoding"] = "gzip, deflate";
                publishrequest.Headers["Accept-Language"] = "fr-FR,en-US";
    
                if (context.Credentials != null)
                {
                    //Use Context Credentials
                    publishrequest.Credentials = context.Credentials;
                }
                else
                {
                    // No specific authentication required
                    publishrequest.UseDefaultCredentials = true;
                }
    
                //Add postback data to the request stream
                stream = publishrequest.GetRequestStream();
                stream.Write(postData, 0, postData.Length);
                stream.Close();
                stream.Dispose();
    
                //Perform the postback
                HttpWebResponse publishResponse = (HttpWebResponse) publishrequest.GetResponse();
    
                //Make sure the response is OK and that it was redirected to the right page
                if (publishResponse.StatusCode != HttpStatusCode.OK || publishResponse.ResponseUri.AbsolutePath != "/sites/contentTypeHub/_layouts/15/ManageContentType.aspx")
                {
                    //Log Something went wrong...
                }
    
                publishResponse.Close();
                publishResponse.Dispose();


    Brad

    • Marked as answer by bgarner Tuesday, October 18, 2016 12:56 PM
    Tuesday, October 18, 2016 12:56 PM
  • Hi,

    Thanks for your sharing.

    Best Regards,

    Lee


    Please remember to mark the replies as an answers if they help and unmark them if they provide no help.
    If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com

    Wednesday, October 19, 2016 1:14 AM