Json 通过 GRAPH 在 Azure AD 中更新用户时出现序列化错误
Json serialization error when updating user in Azure AD via GRAPH
我正在使用 Microsoft.Graph 库 here 更新 Azure AD 中的用户。这对某些用户有效,但对其他用户无效。我的代码如下所示:
public async Task<User> UpdateUser(AdUser adUser)
{
var graphServiceClient = new GraphServiceClient(_azureAuthenticationProvider);
var user = await GetUser(adUser.UserPrincipalName);
user.GivenName = adUser.GivenName;
user.Surname = adUser.LastName;
user.DisplayName = adUser.DisplayName;
user.Department = adUser.Department;
user.AccountEnabled = adUser.AccountEnabled;
await graphServiceClient.Users[user.UserPrincipalName].Request().UpdateAsync(user);
await UpdateUserGroups(adUser);
return await GetUser(adUser.UserPrincipalName);
}
AdUser class 相当基础,仅包括要更新的属性:
public class AdUser
{
public string UserPrincipalName { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string GivenName { get; set; }
public string LastName { get; set; }
public string DisplayName { get; set; }
public string Department { get; set; }
public List<string> OldGroups { get; set; }
public List<string> OldRoles { get; set; }
public List<string> NewGroups { get; set; }
public List<string> NewRoles { get; set; }
public bool AccountEnabled { get; set; }
public bool ForceChangePasswordNextSignIn { get; set; }
}
对于要更新的前三个用户,这很好用。在第四个用户上,我收到一个通用的 AggregateException 消息,"Exception of type 'Microsoft.Graph.ServiceException' was thrown."
启动 Fiddler 显示请求失败:
{
"error": {
"code": "InternalServerError",
"message": "Can not add property department to Newtonsoft.Json.Linq.JObject. Property with the same name already exists on object.",
"innerError": {
"request-id": "b82c4098-6031-40c4-ac6a-4f43746e7b48",
"date": "2016-07-12T05:55:08"
}
}
}
如果我单步执行代码,我可以看到错误发生在这一行:
await graphServiceClient.Users[user.UserPrincipalName].Request().UpdateAsync(user);
这总是发生在同一个用户身上。有什么想法吗?
谢谢!!!
更新 1:
为了完整起见,我的 GetUser 方法如下所示:
public const string AdUserFields = "UserPrincipalName,DisplayName,GivenName,Surname,Department,MemberOf,AccountEnabled";
public async Task<User> GetUser(string userPrincipalName, string fields = AdUserFields)
{
var graphServiceClient = new GraphServiceClient(_azureAuthenticationProvider);
var user = await graphServiceClient.Users[userPrincipalName].Request().Select(fields).GetAsync();
return user;
}
更新二:
请求和响应如下所示。请注意,我没有构建 JSON,SDK 会为我构建。我知道请求中的重复键:
请求:
PATCH https://graph.microsoft.com/v1.0/users/jane.doe@contoso.onmicrosoft.com HTTP/1.1
SdkVersion: graph-dotnet-1.0.1
Authorization: Bearer <token>
Cache-Control: no-store, no-cache
Content-Type: application/json
Host: graph.microsoft.com
Content-Length: 478
Expect: 100-continue
{"accountEnabled":true,"businessPhones":[],"department":"department","displayName":"Jane Doe (department)","givenName":"Jane","surname":"Doe","userPrincipalName":"jane.doe@contoso.onmicrosoft.com","id":"aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa","@odata.context":"https://graph.microsoft.com/v1.0/$metadata#users/$entity","givenName":null,"jobTitle":null,"mail":null,"mobilePhone":null,"officeLocation":null,"preferredLanguage":null,"surname":null}
响应:
HTTP/1.1 500 Internal Server Error
Cache-Control: private
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/8.5
request-id: 2c0437b3-2438-4a34-bf70-937bec2143d1
client-request-id: 2c0437b3-2438-4a34-bf70-937bec2143d1
x-ms-ags-diagnostic: {"ServerInfo":{"DataCenter":"SouthEast Asia","Slice":"SliceB","ScaleUnit":"001","Host":"AGSFE_IN_0","ADSiteName":"SIN"}}
Duration: 30.6384
X-Powered-By: ASP.NET
Date: Wed, 13 Jul 2016 03:08:14 GMT
142
{
"error": {
"code": "InternalServerError",
"message": "Can not add property givenName to Newtonsoft.Json.Linq.JObject. Property with the same name already exists on object.",
"innerError": {
"request-id": "2c0437b3-2438-4a34-bf70-937bec2143d1",
"date": "2016-07-13T03:08:14"
}
}
}
0
您请求中的 json 数据无效,它添加了重复的 属性、givenName 和 surname如下图:
请删除重复的并确保 json 数据有效您可以从 here.
检查它
要更新用户,我们只需要提供我们想要的更改字段。例如,这里是为用户更新部门的示例,供您参考:
var user = graphserviceClient.Me.Request();
var newUser = new User();
newUser.Department = "dep1";
var updateUser=await user.UpdateAsync(newUser);
我已将此归结为我们将 JSON 数据反序列化到各自模型的方式中的错误。模型属性归因于标准 .NET 数据协定。但是,我们使用 NewtonSoft 来完成实际的 JSON 工作。两者的结合导致属性的空值被错误地放入 AdditionalData 字典 属性(未知值的 "catch-all" 桶)。
下一次 SDK 更新时将发布此问题的修复程序。您可以跟踪它 here 前进。
要在短期内解决此问题,您可以遍历 AdditionalData 字典并删除键与模型上已知 属性 匹配的任何条目。如果您在发送更新之前执行此操作,它应该可以正常工作。
更多详情
可以在我们的 SDK 之外普遍重现此错误。例如:
<!-- language: c# -->
public class User
{
[DataMember(EmitDefaultValue = false, IsRequired = false, Name = "name")]
public string Name { get; set; }
[DataMember(EmitDefaultValue = false, IsRequired = false, Name = "department")]
public string Department { get; set; }
[JsonExtensionData(ReadData = true, WriteData = true)]
public IDictionary<string, object> AdditionalData { get; set; }
}
void SomeFunction()
{
string json = @"{ 'name': 'Bob Smith', 'department': null }";
var user = JsonConvert.DeserializeObject<User>(json);
// Inspecting user here will show the Name property with the correct
// value, the Department property with a null value, but will also
// have a "department = null" key / value pair incorrectly in the
// AdditionalData property.
}
我正在使用 Microsoft.Graph 库 here 更新 Azure AD 中的用户。这对某些用户有效,但对其他用户无效。我的代码如下所示:
public async Task<User> UpdateUser(AdUser adUser)
{
var graphServiceClient = new GraphServiceClient(_azureAuthenticationProvider);
var user = await GetUser(adUser.UserPrincipalName);
user.GivenName = adUser.GivenName;
user.Surname = adUser.LastName;
user.DisplayName = adUser.DisplayName;
user.Department = adUser.Department;
user.AccountEnabled = adUser.AccountEnabled;
await graphServiceClient.Users[user.UserPrincipalName].Request().UpdateAsync(user);
await UpdateUserGroups(adUser);
return await GetUser(adUser.UserPrincipalName);
}
AdUser class 相当基础,仅包括要更新的属性:
public class AdUser
{
public string UserPrincipalName { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string GivenName { get; set; }
public string LastName { get; set; }
public string DisplayName { get; set; }
public string Department { get; set; }
public List<string> OldGroups { get; set; }
public List<string> OldRoles { get; set; }
public List<string> NewGroups { get; set; }
public List<string> NewRoles { get; set; }
public bool AccountEnabled { get; set; }
public bool ForceChangePasswordNextSignIn { get; set; }
}
对于要更新的前三个用户,这很好用。在第四个用户上,我收到一个通用的 AggregateException 消息,"Exception of type 'Microsoft.Graph.ServiceException' was thrown."
启动 Fiddler 显示请求失败:
{
"error": {
"code": "InternalServerError",
"message": "Can not add property department to Newtonsoft.Json.Linq.JObject. Property with the same name already exists on object.",
"innerError": {
"request-id": "b82c4098-6031-40c4-ac6a-4f43746e7b48",
"date": "2016-07-12T05:55:08"
}
}
}
如果我单步执行代码,我可以看到错误发生在这一行:
await graphServiceClient.Users[user.UserPrincipalName].Request().UpdateAsync(user);
这总是发生在同一个用户身上。有什么想法吗?
谢谢!!!
更新 1: 为了完整起见,我的 GetUser 方法如下所示:
public const string AdUserFields = "UserPrincipalName,DisplayName,GivenName,Surname,Department,MemberOf,AccountEnabled";
public async Task<User> GetUser(string userPrincipalName, string fields = AdUserFields)
{
var graphServiceClient = new GraphServiceClient(_azureAuthenticationProvider);
var user = await graphServiceClient.Users[userPrincipalName].Request().Select(fields).GetAsync();
return user;
}
更新二: 请求和响应如下所示。请注意,我没有构建 JSON,SDK 会为我构建。我知道请求中的重复键:
请求:
PATCH https://graph.microsoft.com/v1.0/users/jane.doe@contoso.onmicrosoft.com HTTP/1.1
SdkVersion: graph-dotnet-1.0.1
Authorization: Bearer <token>
Cache-Control: no-store, no-cache
Content-Type: application/json
Host: graph.microsoft.com
Content-Length: 478
Expect: 100-continue
{"accountEnabled":true,"businessPhones":[],"department":"department","displayName":"Jane Doe (department)","givenName":"Jane","surname":"Doe","userPrincipalName":"jane.doe@contoso.onmicrosoft.com","id":"aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa","@odata.context":"https://graph.microsoft.com/v1.0/$metadata#users/$entity","givenName":null,"jobTitle":null,"mail":null,"mobilePhone":null,"officeLocation":null,"preferredLanguage":null,"surname":null}
响应:
HTTP/1.1 500 Internal Server Error
Cache-Control: private
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/8.5
request-id: 2c0437b3-2438-4a34-bf70-937bec2143d1
client-request-id: 2c0437b3-2438-4a34-bf70-937bec2143d1
x-ms-ags-diagnostic: {"ServerInfo":{"DataCenter":"SouthEast Asia","Slice":"SliceB","ScaleUnit":"001","Host":"AGSFE_IN_0","ADSiteName":"SIN"}}
Duration: 30.6384
X-Powered-By: ASP.NET
Date: Wed, 13 Jul 2016 03:08:14 GMT
142
{
"error": {
"code": "InternalServerError",
"message": "Can not add property givenName to Newtonsoft.Json.Linq.JObject. Property with the same name already exists on object.",
"innerError": {
"request-id": "2c0437b3-2438-4a34-bf70-937bec2143d1",
"date": "2016-07-13T03:08:14"
}
}
}
0
您请求中的 json 数据无效,它添加了重复的 属性、givenName 和 surname如下图:
要更新用户,我们只需要提供我们想要的更改字段。例如,这里是为用户更新部门的示例,供您参考:
var user = graphserviceClient.Me.Request();
var newUser = new User();
newUser.Department = "dep1";
var updateUser=await user.UpdateAsync(newUser);
我已将此归结为我们将 JSON 数据反序列化到各自模型的方式中的错误。模型属性归因于标准 .NET 数据协定。但是,我们使用 NewtonSoft 来完成实际的 JSON 工作。两者的结合导致属性的空值被错误地放入 AdditionalData 字典 属性(未知值的 "catch-all" 桶)。
下一次 SDK 更新时将发布此问题的修复程序。您可以跟踪它 here 前进。
要在短期内解决此问题,您可以遍历 AdditionalData 字典并删除键与模型上已知 属性 匹配的任何条目。如果您在发送更新之前执行此操作,它应该可以正常工作。
更多详情
可以在我们的 SDK 之外普遍重现此错误。例如:
<!-- language: c# -->
public class User
{
[DataMember(EmitDefaultValue = false, IsRequired = false, Name = "name")]
public string Name { get; set; }
[DataMember(EmitDefaultValue = false, IsRequired = false, Name = "department")]
public string Department { get; set; }
[JsonExtensionData(ReadData = true, WriteData = true)]
public IDictionary<string, object> AdditionalData { get; set; }
}
void SomeFunction()
{
string json = @"{ 'name': 'Bob Smith', 'department': null }";
var user = JsonConvert.DeserializeObject<User>(json);
// Inspecting user here will show the Name property with the correct
// value, the Department property with a null value, but will also
// have a "department = null" key / value pair incorrectly in the
// AdditionalData property.
}