将 Microsoft Graph ListItem 输出转换为相应的 C# 类型

Rob*_*ins 6 c# json sharepoint-list sharepoint-online microsoft-graph-api

通过 SharePoint 和 MS Graph 的组合提供的“帮助”,将 JSON 数据转换为类型化数据模型的工作似乎变得更加复杂。:-)

我在 Microsoft 365 中有一个 SharePoint 列表,我通过 C# 中的图形 API 访问该列表,其中查询目标是一个类型化类,其属性与 SharePoint 列表列属性相同。

类Graph API 返回It 需要变为 an类型的ListItema 中的结果,我可以通过序列化/反序列化往返从查询结果中获取列表来实现这一点,如下所示:Fields.AdditionalDataDictionary<string,object{System.Text.Json.JsonElement}>IEnumerable<DataItem>

var backToJSON = ListItems.Select(o => System.Text.Json.JsonSerializer.Serialize(o.Fields.AdditionalData));
var stronglyTypedItems = backToJSON.Select(jsonO => System.Text.Json.JsonSerializer.Deserialize<DataItem>(jsonO));
Run Code Online (Sandbox Code Playgroud)

有没有办法做到这一点,无论是使用更智能的 OData 还是我没见过的 Graph API 中的某些东西,而不需要使用以前的 JSON 并通过 JSON 序列化器将其发送回两次?

更多详细信息如下:Graph Explorer 的输出 JSON 示例,其中value包含以下数组:

"value" : [ 
    { "id": "1001, 
      "fields": { 
        "Column" : "true", 
        "Column2" : "value2", 
        "Column3" : "65" 
      } 
    }, 
    { "id": "1002, 
      "fields": { 
  <and so forth until the array terminates>
  ]
}
Run Code Online (Sandbox Code Playgroud)

对应的 C# 类(字面上使用“将 JSON 粘贴为类”构建):

Public class DataItem {
  public bool Column {get; set;}
  public string Column2 {get; set;}
  public int Column3 {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

C# Graph API 中的“Helper”类大部分转换为我实际需要的字段数组:

        private static GraphServiceClient graphClient;

        public static IListItemsCollectionRequest LicenseExpirationsList => graphClient
            .Sites["<guid>"]
            .Lists["<nameOfList>"].Items
            .Request()
            .Header("Accept", "application/json;odata.metadata=none")
            .Select("fields,id")
            .Expand("fields");

            var ListItems = (await GraphHelper.LicenseExpirationsList.GetAsync()).CurrentPage;


// JSON round tripping through JSONSerializer to get the strong type...
// But why? ListItems.Fields.AdditionalData is a Dictionary of JSON elements in the first place!

            var backToJSON = ListItems.Select(o => System.Text.Json.JsonSerializer.Serialize(o.Fields.AdditionalData));
            var stronglyTypedItems = backToJSON.Select(jsonO => System.Text.Json.JsonSerializer.Deserialize<DataItem>(jsonO));
 

            return stronglyTypedItems;

Run Code Online (Sandbox Code Playgroud)

wei*_*hch 4

您可以自定义客户端的 JSON 序列化以返回 default 的派生类型FieldValueSet

首先,定义您自己的扩展FieldValueSet

public class FieldValueSetWithDataItem : FieldValueSet
{
    public bool Column { get; set; }
    public string Column2 { get; set; }
    public int Column3 { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

其次,实现您自己的 JSON 转换器

class CustomFieldValueSetJsonConverter : JsonConverter<FieldValueSet>
{
    private static readonly JsonEncodedText ODataTypeProperty 
        = JsonEncodedText.Encode("@odata.type");
    private static readonly JsonEncodedText IdProperty 
        = JsonEncodedText.Encode("id");
    private static readonly JsonEncodedText ColumnProperty 
        = JsonEncodedText.Encode("Column");
    private static readonly JsonEncodedText Column2Property 
        = JsonEncodedText.Encode("Column2");
    private static readonly JsonEncodedText Column3Property
        = JsonEncodedText.Encode("Column3");

    public override FieldValueSet Read(ref Utf8JsonReader reader,
        Type typeToConvert, JsonSerializerOptions options)
    {
        var result = new FieldValueSetWithDataItem();
        using var doc = JsonDocument.ParseValue(ref reader);
        var root = doc.RootElement;

        foreach (var element in root.EnumerateObject())
        {
            if (element.NameEquals(ODataTypeProperty.EncodedUtf8Bytes))
            {
                result.ODataType = element.Value.GetString();
            }
            else if (element.NameEquals(IdProperty.EncodedUtf8Bytes))
            {
                result.Id = element.Value.GetString();
            }
            else if (element.NameEquals(ColumnProperty.EncodedUtf8Bytes))
            {
                result.Column = element.Value.GetBoolean();
            }
            else if (element.NameEquals(Column2Property.EncodedUtf8Bytes))
            {
                result.Column2 = element.Value.GetString();
            }
            else if (element.NameEquals(Column3Property.EncodedUtf8Bytes))
            {
                result.Column3 = element.Value.GetInt32();
            }
            else
            {
                // Capture unknown property in AdditionalData
                if (result.AdditionalData is null)
                {
                    result.AdditionalData = new Dictionary<string, object>();
                }
                result.AdditionalData.Add(element.Name, element.Value.Clone());
            }
        }

        return result;
    }

    public override void Write(Utf8JsonWriter writer,
        FieldValueSet value, JsonSerializerOptions options)
    {
        // To support roundtrip serialization:
        writer.WriteStartObject();

        writer.WriteString(ODataTypeProperty, value.ODataType);
        writer.WriteString(IdProperty, value.Id);

        if (value is FieldValueSetWithDataItem dataItem)
        {
            writer.WriteBoolean(ColumnProperty, dataItem.Column);
            writer.WriteString(Column2Property, dataItem.Column2);
            writer.WriteNumber(Column3Property, dataItem.Column3);
        }

        if (value.AdditionalData is not null)
        {
            foreach (var kvp in value.AdditionalData)
            {
                writer.WritePropertyName(kvp.Key);
                ((JsonElement)kvp.Value).WriteTo(writer);
            }
        }
        
        writer.WriteEndObject();
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,在发出请求时使用 JSON 转换器:

// Use custom JSON converter when deserializing response
var serializerOptions = new JsonSerializerOptions();
serializerOptions.Converters.Add(new CustomFieldValueSetJsonConverter());

var responseSerializer = new Serializer(serializerOptions);
var responseHandler = new ResponseHandler(responseSerializer);

var request = (ListItemsCollectionRequest)client.Sites[""].Lists[""].Items.Request();

var listItems = await request
    .WithResponseHandler(responseHandler)
    .GetAsync();
Run Code Online (Sandbox Code Playgroud)

要访问您的列值:

var col3 = ((FieldValueSetWithDataItem)listItem.Fields).Column3;
Run Code Online (Sandbox Code Playgroud)