2016-08-16 2 views
-2

У меня есть список List<System.Security.Claim>, и я хочу добавить каждое требование асинхронно. Мне любопытно, как выполнить все задачи и установить boolean для последующего использования, чтобы все задачи были выполнены.Как выполнить список задач?

foreach (var claim in claims) 
{ 
    claimTasks.Add(UserManager.AddClaimAsync(user.Id, claim)); 
} 

claimResultSucceeded = Task.WhenAll(claimTasks).IsCompleted; 

Я также попытался это:

foreach (var claim in claims) 
{ 
    claimTasks.Add(Task.Run(() => UserManager.AddClaimAsync(user.Id, claim))); 
} 

claimResultSucceeded = Task.WhenAll(claimTasks).IsCompleted; 

Edit: Как вы можете видеть на фото ниже, задачи бьют неисправное состояние:

{ "A вторая операция началась в этом контексте до того, как завершилась предыдущая операция асинхронная операция . Используйте «ожидание», чтобы гарантировать, что любые асинхронные операции завершены до вызова другого метода в этом контексте. Любой экземпляр членов не гарантируется поточно. "}

enter image description here

+1

Что вы ожидаете от '.IsCompleted'? Укажите, что вы ожидаете от своего кода и что вы наблюдаете за ним. –

+0

@ LasseV.Karlsen .IsCompleted должен содержать результат true или false после выполнения всех задач. Я уточнил вопрос более подробно. – user1477388

+1

@ user1477388 Нет, он возвращает, завершена ли задание или нет, и немедленно ее возвращает. – Servy

ответ

1

Вы уверены? Task.WhenAll будет взять набор задачи (и поэтому принимать любое значение, возвращаемое из этих задач) и верните новую задачу, которую вы можете подождать, как вы уже сказали?

Я собрал следующий пример кода, который в основном показал то, что вы показали (с небольшими бессмысленными данными, чтобы убедиться, что было достаточно для составления) -

static async void Main(string[] args) 
{ 
    // Declare some references to work with (this data is rubbish, it's just here so 
    // that everything compiles) 
    var userManager = new UserManager<User, Key>(null); 
    var user = new User(); 
    var claims = new List<Claim>(); 
    var claimTasks = new List<Task<IdentityResult>>(); 

    // This is basically the code that appears in the question - it compiles fine 
    foreach (var claim in claims) 
    { 
     claimTasks.Add(userManager.AddClaimAsync(user.Id, claim)); 
    } 

    // WhenAll returns a single task that will be completed when all of the individual 
    // claims tasks have completed 
    var claimResults = await Task.WhenAll(claimTasks); 

    // When this happens, you should be able to look at each of the IdentityResults 
    // instances in the claimResults array to ensure they all succeeded 
    // Note: I'm presuming a little here since I'm not too familiar with these types, but 
    // it seems reasonable that the Succeeded flag on each IdentityResult should indicate 
    // whether or not it was successfully retrieved 
    var allRequestsSucceeded = claimResults.All(c => c.Succeeded); 
} 

// This struct and class have no purpose other than making the code compile 
public struct Key : IEquatable<Key> 
{ 
    public bool Equals(Key other) { throw new NotImplementedException(); } 
} 

public class User : IUser<Key> 
{ 
    public Key Id 
    { 
     get { throw new NotImplementedException(); } 
    } 

    public string UserName 
    { 
     get { throw new NotImplementedException(); } 
     set { throw new NotImplementedException(); } 
    } 
} 
+0

Как вы можете видеть на фотографии, которую я только что добавил, код будет компилироваться и исполнять; однако задачи никогда не выполняются. Они остаются в неисправном состоянии, потому что происходит ошибка (я этого раньше не осознавал). – user1477388

+0

А, я вижу. Первоначально в вашем вопросе говорилось, что это проблема с возвращаемым типом, с которой вы столкнулись - IdentityResult, где вам нужен bool, поэтому я предположил, что код не компилируется. Я собираюсь настроить свой ответ (для будущего потомства), принимая во внимание комментарий @Lasse V.Карлен, который полностью прав (и я не могу поверить, что я не заметил изначально!), Что «IsCompleted» - это неправильная проверка, и что ожидаемая задача WhenAll должна быть ожидаемой. Когда это завершено, все ваши дочерние задачи завершены (независимо от того, были ли они успешными или неудачными, может быть другое дело). –

1

Ваша новая ошибка исходит от Entity Framework. Вы можете использовать только одну операцию async для экземпляра контекста db. Просто сделайте это:

foreach (var claim in claims) 
{ 
    var result = await UserManager.AddClaimAsync(user.Id, claim); 
    if (result.Succeded == false) { 
     // Handle the error 
    } 
} 

EDIT: Инкорпорейтед @Dan Roberts совет.

+0

С этим, как я могу проверить, чтобы все задачи были успешно завершены? – user1477388

+1

Если вы настроите это на "var addClaimResult = ожидание UserManager.AddClaimAsync (user.Id, Claim);" внутри цикла, тогда вы можете проверить «addClaimResult.Succeeded» каждый вызов и установить флаг, если кто-либо из них говорит, что им не удалось. Этот подход не будет работать параллельно, но будет асинхронным, поскольку поток не будет привязан, пока каждый вызов AddClaimAsync обрабатывается, что является ценным. Я думаю, что Майк, вероятно, знает эти классы идентичности намного лучше, чем я, и этот ответ может быть лучше моего (поэтому он заслуживает и получает от меня большой голос). –

+0

Хорошо поймать @DanRoberts, я отредактировал, чтобы добавить проверку результата. –