sp-dev-docs icon indicating copy to clipboard operation
sp-dev-docs copied to clipboard

Expose SPContentTypeEntityData so we can use ParentContentTypeId

Open patrick-rodgers opened this issue 6 years ago • 21 comments
trafficstars

Category

  • [ ] Question
  • [ ] Typo
  • [X] Bug
  • [ ] Additional article idea

Expected or Desired Behavior

When creating a new content type via REST we do a post to the collection with a set of data. These parameters are defined by the SPContentTypeEntityData in the source code, however this type cannot be resolved (see observed behavior). It is expected that we could call the method with the defined type using all the properties.

Ideally we could create a new content type and specify the entire new content type id, but that is a bigger change.

Observed Behavior

If you make the POST request with a plain object with a metadata type of "SP.ContentTypeEntityData", "SPContentTypeEntityData", or "ContentTypeEntityData" you get an error below:

{"odata.error":{"code":"-1, Microsoft.SharePoint.Client.InvalidClientQueryException","message":{"lang":"en-US","value":"A type named 'ContentTypeEntityData' could not be resolved by the model. When a model is available, each type name must resolve to a valid type."}}}

Steps to Reproduce

Craft a POST request to the rest API and try to specify ParentContentTypeId in that data.

patrick-rodgers avatar Jan 16 '19 16:01 patrick-rodgers

Thank you for reporting this issue. We will be triaging your incoming issue as soon as possible.

msft-github-bot avatar Jan 16 '19 16:01 msft-github-bot

Is there any update to this? Unfortunately, this results in not being able to create a content type and define a parent content type. With this bug, the new content type always is a child of Item. See also here: https://stackoverflow.com/questions/55529315/how-to-create-site-content-type-with-id-using-rest-api

AlNoes avatar Jun 03 '19 12:06 AlNoes

Hello guys! It's a pleasure to greet you. Is there any news about this error?

facujuarez avatar Apr 07 '20 19:04 facujuarez

Hi guys! I would like to know if you have any news.

fridrichovsky avatar May 14 '20 08:05 fridrichovsky

Good day @patrick-rodgers , i see this attached to bug about id. Does this also apply for issue when cannot assign parent to created content type? Checked today still not working and defaulting to Item as parent.

ValerasNarbutas avatar Sep 18 '20 10:09 ValerasNarbutas

I raised question to Microsoft Support and they don't plan fix this bug. I had to use workaround through Azure Functions where I use CSOM for this particular part.

fridrichovsky avatar Sep 21 '20 07:09 fridrichovsky

Is there an update on this topic? This won't be fixed? Really? Is there a known reason?

Face the same issue and can confirm it's always using the root "item" as content type.

fs366e2spm avatar Feb 11 '21 15:02 fs366e2spm

Any update on this?

vzzdaniel avatar Feb 11 '21 17:02 vzzdaniel

Is there an update on this?

CallumCrowley avatar Mar 01 '21 17:03 CallumCrowley

Let's keep it open. Any updates?

klioqc avatar Apr 23 '21 22:04 klioqc

As far I know this bug still persist. I found workaround which can help somebody who cannot use CSOM or JSOM. You can use Site script to define new site content type and specify parent content type name or Id. This site script you can wrap in a Site design and apply this Site design through REST API. Unfortunately this workaround is useful only if you create the same site content type on different sites. And of course you can create multiple Site scripts and Site designs for each content type.

MartinZamazal avatar Apr 26 '21 11:04 MartinZamazal

Late to the party, of course I'm facing the same issue. Creating a new SharePoint site content type through HTTP REST POST defaults to "item" as its parent instead of the one I provided in the body. I find it quite bizarre that confirmed bugs are considered not to be resolved...

joostvdlinden avatar May 11 '21 21:05 joostvdlinden

After spending a weekend in finding out how to create a content type using test I found this. I truly agree it’s strange that Microsoft doesn’t fix this

erapade avatar Apr 10 '22 07:04 erapade

@patrick-rodgers Any updates on this?

I am trying to add a content type to the site with specific ID using @pnp/sp and @pnp/graph. But it seems that both packages ignores the "id" provided, and always creates a content type with different id.

Thanks in advance!

vishalshitole avatar Apr 11 '24 17:04 vishalshitole

Almost 6 years and still open... Has anyone found a workaround ?

nwaelti avatar Sep 20 '24 12:09 nwaelti

Hello @nwaelti, I could not wait so I "solved" this by Azure Functions. I create function that do what I needed AddContenType I used SharePoint libraries there and I call this function from my application that does not allow use .NET because runs on cloud. This works for On-Prem and Online SP.

fridrichovsky avatar Sep 20 '24 13:09 fridrichovsky

Hello @nwaelti, I could not wait so I "solved" this by Azure Functions. I create function that do what I needed AddContenType I used SharePoint libraries there and I call this function from my application that does not allow use .NET because runs on cloud. This works for On-Prem and Online SP.

Oh, great, thx for the tip @fridrichovsky

nwaelti avatar Sep 20 '24 13:09 nwaelti

Hello @nwaelti, I added my code bellow. It is simple code but it works for me. How to create Azure Function from Visual Studio you can find on MS learn sites here. I am calling standard HTTP Request from my application. URL for request you will get from azure function after publish. If you have URL you can call POST request with body where you fill parameters. Body expect JSON: { "NSPLicenseKey": "something", "ParentSiteWebURL": "something", . . . } I am using OAuth for authorization to SP.

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Microsoft.SharePoint.Client;

namespace SharePointAzureFunctions
{
    public static class SharePointAZContentType
    {
        [FunctionName("AddContentType")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            const string Message = "AddContentType user {User} call function from {Address}";
            log.LogInformation(message: Message);
            if (req == null)
            {
                return new BadRequestObjectResult("Empty request!");
            }
            string AccessTokenUTF8 = req.Query["Authorization"];
            string NSPLicenseKey = req.Query["NSPLicenseKey"];
            string ParentSiteWebURL = req.Query["ParentSiteWebURL"];
            string ParentContentTypeID = req.Query["ParentContentTypeID"];
            string SiteWebURL = req.Query["SiteWebURL"];
            string ContentTypeName = req.Query["ContentTypeName"];
            string ContentTypeDescription = req.Query["ContentTypeDescription"];
            string GroupName = req.Query["GroupName"];

            StreamReader Request = new StreamReader(req.Body);
            string requestBody = await Request.ReadToEndAsync().ConfigureAwait(true);
            log.LogInformation(requestBody);
            dynamic data = JsonConvert.DeserializeObject(requestBody);
            AccessTokenUTF8 ??= data?.Authorization;
            NSPLicenseKey ??= data?.NSPLicenseKey;
            ParentSiteWebURL ??= data?.ParentSiteWebURL;
            ParentContentTypeID ??= data?.ParentContentTypeID;
            SiteWebURL ??= data?.SiteWebURL;
            ContentTypeName ??= data?.ContentTypeName;
            ContentTypeDescription ??= data?.ContentTypeDescription;
            GroupName ??= data?.GroupName;
            Request.Dispose();

            var SPClientContext = new ClientContext(ParentSiteWebURL);
            if (AccessTokenUTF8.Length != 0)
            {
                SPClientContext.ExecutingWebRequest += delegate (object sender, WebRequestEventArgs e)
                {
                    //e.WebRequestExecutor.WebRequest.Headers.Add("Authorization", AccessTokenUTF8);
                    e.WebRequest.Headers.Add("Authorization", AccessTokenUTF8);
                };
            }

            Site RootSite = SPClientContext.Site;
            Web ParentWeb = SPClientContext.Web;
            ContentTypeCollection ParentWebCTCollection = ParentWeb.ContentTypes;
            ContentType ParentContentType = ParentWebCTCollection.GetById(ParentContentTypeID);
            try
            {
                await SPClientContext.ExecuteQueryAsync();
            }
            catch (Exception ex)
            {
                return new BadRequestObjectResult(ex.Message);
            }

            Web SPWeb = RootSite.OpenWeb(Uri.UnescapeDataString(new Uri(SiteWebURL).AbsolutePath));
            SPClientContext.Load(SPWeb);
            ContentTypeCollection WebCTCollection = SPWeb.ContentTypes;

            ContentTypeCreationInformation NewContentType = new ContentTypeCreationInformation();
            NewContentType.ParentContentType = ParentContentType;
            NewContentType.Name = ContentTypeName;
            NewContentType.Group = GroupName;
            NewContentType.Description = ContentTypeDescription;
            ContentType ContentType = WebCTCollection.Add(NewContentType);
            try
            {
                SPClientContext.Load(ContentType);
                await SPClientContext.ExecuteQueryAsync();
                SPClientContext.Dispose();
                return (ActionResult)new OkObjectResult(ContentType.Id);
            }
            catch (PropertyOrFieldNotInitializedException ex)
            {
                return new NotFoundObjectResult(ex.Message);
            }
            catch (InvalidQueryExpressionException ex)
            {
                return new BadRequestObjectResult(ex.Message);
            }
            catch (ClientRequestException ex)
            {
                return new BadRequestObjectResult(ex.Message);
            }
            catch (ServerException ex)
            {
                return new BadRequestObjectResult(ex.Message);
            }
            catch (Exception ex)
            {
                return new BadRequestObjectResult(ex.Message);
            }
        }
    }
}

fridrichovsky avatar Sep 20 '24 14:09 fridrichovsky

Thx a milion ❤️

nwaelti avatar Sep 20 '24 14:09 nwaelti

Does this work in Graph API as it is recommended way to use SPO?

klioqc avatar Sep 29 '24 13:09 klioqc

@klioqc I have not tray it. I saw that Graph API have something like "base" property in JSON for content type create. Question is if it works or not. What I know graph API is created over SP REST API. So probably "base" is ignored.

I am using direct SP REST API and what I have is libraries that use direct SP URLs. I am afraid that libraries require direct URLs, but as I wrote I have not test it so it is not 100% truth.

fridrichovsky avatar Oct 04 '24 05:10 fridrichovsky

Does this work in Graph API as it is recommended way to use SPO?

Seems like the id property is ignored... So still no way to do this with REST or Graph sad panda 🐼

tarjeieo avatar Dec 12 '24 08:12 tarjeieo

Thank you for taking the time to file an issue. We periodically archive older or inactive issues as part of our issue management process, which automatically closes them once they are archived.

If you’d like to understand more about why and how we handle archived (closed) issues, please see Our approach to closed issues.

We appreciate your contribution and if this is still an active issue with the latest SPFx versions, please do resubmit the details. We needed to perform a cleanup, so that we can start with a clean table with a new process. We apologize for the inconvenience this might cause.

github-actions[bot] avatar May 02 '25 14:05 github-actions[bot]