пакетная обработка: userPrincipalName уже существует при попытке добавить несколько пользователей async в AAD

Я пытаюсь добавить нескольких пользователей асинхронно с графиком AAD Вот так:

IUser user1 = ...;
IUser user2 = ...;
IUser user3 = ...;
List<Task> addTasks = new List<Task>();
addTasks.Add(activeDirectoryClient.Users.AddUserAsync(user1));
addTasks.Add(activeDirectoryClient.Users.AddUserAsync(user2));
addTasks.Add(activeDirectoryClient.Users.AddUserAsync(user3));
await Task.WhenAll(addTasks);

Я получаю это сообщение об ошибке:

{"odata.error": {"code": "Request_BadRequest", "message": {"lang": "en", "value": "Другой объект с таким же значением для свойства userPrincipalName уже существует."}, " values ​​": [{" item ":" PropertyName "," value ":" userPrincipalName "}, {" item ":" PropertyErrorCode "," value ":" ObjectConflict "}]}}

Если я использую этот код:

IUser user1 = ...;
IUser user2 = ...;
IUser user3 = ...;
List<Task> addTasks = new List<Task>();
await activeDirectoryClient.Users.AddUserAsync(user1);
await activeDirectoryClient.Users.AddUserAsync(user2);
await activeDirectoryClient.Users.AddUserAsync(user3);

Это хорошо работает.

Может быть, мы не можем добавить несколько пользователей в AAD одновременно?

РЕДАКТИРОВАТЬ Вот часть пользователей:

IUser newStudentUser = new User
{
    DisplayName = $"Etudiant de l'école {school}",
    UserPrincipalName = $"etudiant-{school}@........fr",
    AccountEnabled = true,
    MailNickname = $"Etudiant {school}",
    UsageLocation = "US",
    PasswordProfile = new PasswordProfile
    {
        Password = "......."
    }
};
IUser newTeacherUser = new User
{
    DisplayName = $"Professeur de l'école {school}",
    UserPrincipalName = $"professeur-{school}@........fr",
    AccountEnabled = true,
    MailNickname = $"Professeur {school}",
    UsageLocation = "US",
    PasswordProfile = new PasswordProfile
    {
        Password = "......."
    }
};
IUser newDirectorUser = new User
{
    DisplayName = $"Directeur de l'école {school}",
    UserPrincipalName = $"directeur-{school}@........fr",
    AccountEnabled = true,
    MailNickname = $"Directeur {school}",
    UsageLocation = "US",
    PasswordProfile = new PasswordProfile
    {
        Password = "......."
    }
};

person trenoncourt    schedule 15.04.2016    source источник
comment
Возможно, ваши ... содержат код, в котором некоторые объекты оказались общими для всех 3 user переменных, и поэтому установка значения для одной из них устанавливает одинаковое значение для всех 3 независимых переменных. Я бы подумал, что это более вероятно. Не могу подтвердить, так как вы пропустили этот код.   -  person Damien_The_Unbeliever    schedule 15.04.2016
comment
Я добавил часть создания пользователей. Но я не думаю, что это может быть так, потому что он работает с методом await ...; await ...; await ...;   -  person trenoncourt    schedule 15.04.2016
comment
Можете ли вы переименовать свой вопрос, чтобы он относился к пакетной обработке?   -  person Thomas    schedule 18.04.2016


Ответы (1)


В вашем случае вы хотите создать несколько пользователей в пакетном режиме.

В настоящее время GraphClient поддерживает пакетную обработку, но есть некоторые ограничения (Пакетная обработка | Концепции Graph API):

  • Один пакет может содержать не более пяти запросов и / или объединенных наборов изменений.
  • Набор изменений может содержать максимум одну модификацию исходного объекта и до 20 операций добавления и удаления ссылки вместе. Все операции в наборе изменений должны выполняться с одной исходной сущностью.

Таким образом, в вашем случае вы не можете создать более 5 пользователей в пакетном режиме.

При добавлении сущности в клиент Graph API вы можете отложить выполнение запроса с помощью параметра deferredSave.

await activeDirectoryClient.Users.AddUserAsync(user, deferredSave: true);

У клиента Graph API есть DataServiceContextWrapper, который отслеживает изменения. Он предоставляет SaveChanges(Async) метод.

await activeDirectoryClient.Context.SaveChangesAsync();

Вызывая этот метод, вы можете указать SaveChangesOptions:

  • Пакет: все ожидающие изменения сохраняются в одном пакетном запросе.
  • BatchWithIndependentOperations: тот, который вы хотите использовать, потому что создание пользователя должно происходить в одном запросе.
  • ContinueOnError: ожидающие изменения сохраняются с помощью нескольких запросов к серверу, и операция продолжается после возникновения ошибки.
  • Нет: ожидающие изменения сохраняются с помощью нескольких запросов к серверу, но операция останавливается при первом сбое (по умолчанию).
  • PatchOnUpdate:
  • ReplaceOnUpdate: ожидающие обновления выполняются путем замены всех значений объекта в источнике данных значениями из обновленного объекта.

Теперь у вас достаточно информации, чтобы написать код для пакетного создания пользователей:

// Only 5 users per batch !!!!
var user1 = ...;
var user2 = ...;
var user3 = ...;
await activeDirectoryClient.Users.AddUserAsync(newStudentUser, deferredSave: true);
await activeDirectoryClient.Users.AddUserAsync(newTeacherUser, deferredSave: true);
await activeDirectoryClient.Users.AddUserAsync(newDirectorUser, deferredSave: true);

// In debug mode, you should use the SaveChangesAsync method with the default options
// Becasue the BatchWithIndependentOperations will not throw any exception even if there is a problem while creating the user.
//await activeDirectoryClient.Context.SaveChangesAsync();
await activeDirectoryClient.Context
    .SaveChangesAsync(SaveChangesOptions.BatchWithIndependentOperations);
person Thomas    schedule 17.04.2016
comment
Я использую тот же код, что и ваш, для создания списка пользователей. но я получаю исключение: Контекст уже отслеживает объект. Я использую ваш тот же код, но со списком пользователей и циклом, это действительно расстраивает, поскольку я застрял с этой ошибкой из-за пару дней - person shakram02; 21.07.2016
comment
@AhmedHamdy, откуда у тебя список? Как вы составляете свой список пользователей? Не стесняйтесь задавать новый вопрос и размещать свой код - person Thomas; 21.07.2016
comment
Спасибо за быстрый ответ, пожалуйста, найдите мой вопрос здесь stackoverflow.com/questions/38429710/ - person shakram02; 22.07.2016
comment
Хорошо, я посмотрю и скажу тебе, найду ли я что-нибудь - person Thomas; 22.07.2016
comment
Большое спасибо за ваши усилия, я нашел ошибку в своем коде - person shakram02; 25.07.2016
comment
@AhmedHamdy, не беспокойся, это что-то, что может помочь кому-то другому? - person Thomas; 25.07.2016
comment
на самом деле это была ошибка новичка, так как я не создавал нового каждого пользователя и использовал один и тот же объект вместо создания нового - person shakram02; 25.07.2016