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



将JSON数据转换为类型化数据模型的工作似乎由于"help"而变得更加复杂。SharePoint和MS Graph的结合。: -)

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

ListItem类图API返回Dictionary<string,object{System.Text.Json.JsonElement}>类型的aFields.AdditionalData的结果,它需要成为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));

是否有一种方法可以做到这一点,无论是更智能的OData还是我没有见过的图形API中的某些东西,而不采取曾经是JSON并通过JSON序列化器发送它两次?

详情如下:从图形资源管理器输出JSON示例,其中value包含一个数组:

"value" : [ 
{ "id": "1001, 
"fields": { 
"Column" : "true", 
"Column2" : "value2", 
"Column3" : "65" 
} 
}, 
{ "id": "1002, 
"fields": { 
<and so forth until the array terminates>
]
}

对应的c#类(字面意思是使用"Paste JSON as Class "):

Public class DataItem {
public bool Column {get; set;}
public string Column2 {get; set;}
public int Column3 {get; set;}
}

"Helper"c# Graph API中的类提供的大多是将转换为我实际需要的字段数组:

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;

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

首先,定义您自己的扩展FieldValueSet:
public class FieldValueSetWithDataItem : FieldValueSet
{
public bool Column { get; set; }
public string Column2 { get; set; }
public int Column3 { get; set; }
}
第二,实现你自己的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();
}
}
最后,在发出请求时使用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();

访问列值:

var col3 = ((FieldValueSetWithDataItem)listItem.Fields).Column3;

您可能会发现GraphServiceClient的HttpProvider在这种情况下很有帮助:

var listItemsCollectionRequest = graphServiceClient
.Sites["<guid>"]
.Lists["<nameOfList>"]
.Items
.Request()
.Header("Accept", "application/json;odata.metadata=none")
.Select("fields,id")
.Expand("fields");
using (var requestMessage = listItemsCollectionRequest.GetHttpRequestMessage())
{
using var responseMessage = await graphServiceClient.HttpProvider.SendAsync(requestMessage);
//deserialize the response body into DataItem
}

通过使用HttpProvider,你可以直接处理来自Graph API的响应,并将响应体反序列化到你的自定义类中。

相关内容

  • 没有找到相关文章

最新更新