sp-dev-docs
sp-dev-docs copied to clipboard
Expose SPContentTypeEntityData so we can use ParentContentTypeId
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.
Thank you for reporting this issue. We will be triaging your incoming issue as soon as possible.
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
Hello guys! It's a pleasure to greet you. Is there any news about this error?
Hi guys! I would like to know if you have any news.
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.
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.
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.
Any update on this?
Is there an update on this?
Let's keep it open. Any updates?
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.
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...
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
@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!
Almost 6 years and still open... Has anyone found a workaround ?
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.
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
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);
}
}
}
}
Thx a milion ❤️
Does this work in Graph API as it is recommended way to use SPO?
@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.
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 🐼
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.