pnp / pnpcore

The PnP Core SDK is a modern .NET SDK designed to work for Microsoft 365. It provides a unified object model for working with SharePoint Online and Teams which is agnostic to the underlying API's being called
https://aka.ms/pnp/coresdk/docs
MIT License
299 stars 191 forks source link

Cannot update MaxLength property on a text field #1541

Open tomasz-sintel opened 4 weeks ago

tomasz-sintel commented 4 weeks ago

Category

Describe the bug

After retrieving fields from a list, I am trying to update some of their properties. I query the fields with the f => f.All include flag to have all of the props present. At the moment I am only interested in Single Line Text Field fields, so I filter them out. I can see the prop values loaded properly. I am able to update properties like Title, Required, Unique, Indexed successfully. But after I had added setting the MaxLength property, the code fails with a message: The property 'MaxLength' does not exist on type 'SP.Field'. Make sure to only use property names that are defined by the type.

I am working with a batch to group multiple field updates into a single operation. But I have also tried to update each field individually with no success.

Steps to reproduce

var list = await context.Web.Lists.GetByIdAsync(listId);
var fields = await list.Fields.QueryProperties(f => f.All)
    .ToListAsync(cancellationToken);
var allFields = fields.ToList();

// get any single line text field by name or type
var field = fields.FirstOrDefault(f => f.FieldTypeKind == FieldType.Text);

// this batch does not make sense here, but I am working on multiple fields before pushing changes to server
var batch = context.NewBatch();
field.Required = true;
field.MaxLength = 120;
await field.UpdateBatchAsync(batch);

// this line throws the exception
await context.ExecuteAsync(batch);

Expected behavior

I expect the request not to fail :)

Environment details (development & target environment)

Additional context

Exception details: Message: SharePoint Rest service exception Source: PnP.Core StackTrace:

   at PnP.Core.Services.BatchClient.ProcessSharePointRestBatchResponseContent(Batch batch, String batchResponse, Dictionary`2 responseHeadersToPropagate)
   at PnP.Core.Services.BatchClient.<ProcessSharePointRestBatchResponse>d__54.MoveNext()
   at PnP.Core.Services.BatchClient.<ExecuteSharePointRestBatchAsync>d__52.MoveNext()
   at PnP.Core.Services.BatchClient.<ExecuteBatch>d__37.MoveNext()
   at PnP.Core.Services.PnPContext.<ExecuteAsync>d__101.MoveNext()
   at <obfuscated>.SharePoint.Infrastructure.FormStructure.FormStructureUpdater.<UpdatePreExistingFieldsAsync>d__9.MoveNext() in <obfuscated>.SharePoint\Infrastructure\FormStructure\FormStructureUpdater.cs:line 118

Inner Exception: null Error (partial): HttpResponseCode: 400 Message: The property 'MaxLength' does not exist on type 'SP.Field'. Make sure to only use property names that are defined by the type. Type: SharePointRestServiceError HResult: -2146233088

Additionally...

I have peeked the request data and the type of the field being updated in the request payload is set to SP.Field. I am not sure, but maybe this value should be set to the specific field's type, e.g. SP.FieldText. I have a suspicion that setting other field types' exclusive properties may lead to the same problem.

Thanks for your contribution! Sharing is caring.

jansenbe commented 3 weeks ago

@tomasz-sintel : can you try updating the SchemaXmlWithResourceTokens property of the field. See https://github.com/pnp/pnpcore/discussions/1418

tomasz-sintel commented 3 weeks ago

@jansenbe There is no SchemaXmlWithResourceTokens property on the IField interface. I can update the value with the SchemaXml property, and that's what I had suspected. I didn't want to go that route though, because I was afraid of mixing the use of property setters and SchemaXml setter.

Consider the following piece of code:

public record XmlValue(string AttributeName, string Value);
// ...
// GetUpdatedSchemaXml is just an XML transformation method
field.SchemaXml = GetUpdatedSchemaXml(field.SchemaXml, new XmlValue("MaxLength", "123"));
field.Title = "Some Title";
field.EnforceUniqueValues = true;
field.Indexed = true;
field.Required = true;

await field.UpdateAsync();

In the example above the code only works if the SchemaXml is set as the first operation. If I move it below the field.Required = true; line, the EnforceUniqueValues is not updated in the field, although no error is thrown and the other props are set.

What is your recommendation? Is it safe to keep it as presented above or would I need to turn to setting ALL field props through the SchemaXml now?

From my colleague's experiment I know, that the problem is the same for any dedicated field properties in other field types, e.g. Min and Max props in a number field.

[UPDATE] No, the other properties set after the SchemaXml do not update properly in the list field, sorry. So - the only choice I have is to go exclusively through SchemaXml?

jansenbe commented 3 weeks ago

Like you mentioned in your initial comment, some more testing is needed with using the "right" type when building the update payload (would be a change in Core SDK). In the meantime please try with reading/updating/writing SchemaXML

tomasz-sintel commented 3 weeks ago

Ok, thanks. I'll let you decide what to do with this bug.

jansenbe commented 1 week ago

You've any feedback here @tomasz-sintel ?

tomasz-sintel commented 5 days ago

Yes, from my side working with SchemaXml works provided that this property is used exclusively to set values on the field. My colleague came up with a workaround to make the individual properties work:

((Field)field).Metadata["type"] = "SP.FieldText";

It's suppose to work, but I haven't used it, since I already got it to work with the SchemaXml. The core reason as to why the type in the Metadata is always set to SP.Field is more complex and this is where I see the real fix of the issue. Unfortunately we do not have scope for this, especially when we got it to work in the end.