2016-01-26 6 views
0

Мне нужно реализовать собственный поставщик хранилища для aspnetidentity. У меня был хороший взгляд, и я нашел немало. Однако они кажутся мне неправильными.Асинхронный код, вводящий в заблуждение идентификатор aspnet

Мое недоразумение в том, что если у вас есть метод, который заканчивается на «асинхронный», чем он должен быть асинхронным.

См. Пример, взятый из чьего-то кода, и это разбросано повсюду.

Я найти ниже вводит в заблуждение, так как это не ASync вовсе не от того, что я могу видеть:

public Task<TUser> FindByIdAsync(int userId) 
    { 
     TUser result = userTable.GetUserById(userId) as TUser; //this is not async 
     if (result != null) 
     { 
      return Task.FromResult<TUser>(result); 
     } 

     return Task.FromResult<TUser>(null); 
    } 

это должно кодироваться как это ?:

 public async Task<TUser> FindByIdAsync(int userId) 
     { 

      TUser result = userTable.GetUserByIdAsync(userId) as TUser; 
      if (result != null) 
      { 
       return await Task.FromResult<TUser>(result); 
      } 

      return await Task.FromResult<TUser>(null); 
     } 

    Questions? 
  1. Правильно ли делать «Task.FromResult»? То, что я имею в виду, делает «Task.FromResult на самом деле превращается в синхронное? Какой она должна быть?

  2. Что такое правильный способ кодирования выше? Насчет configureAwait (ложь) должна быть асинхронной» Все пути вниз, включая datalayer избежать запирания»

любого образец код/​​фрагмент кода будет оценен

большого спасибо за любую обратную связь

+0

первый один только оборачивает синхронный вызов 'GetUserById' до * поддельный * это в асинхронном (по крайней мере, вы можете использовать его с ждать сейчас) - второй из них является абсолютно бесполезно, поскольку вы можете просто использовать 'userTable.GetUserByIdAsync' - вы просто распаковываете и переупаковываете его. – Carsten

+0

Откуда берутся« GetUserByIdAsync »?Это действительно существует? Если это так, просто верните его результат в качестве Задачи . –

+0

@PanagiotisKanavos Я добавил GetUserByIdAsync как пример сам из того, что, как мне кажется, должно быть – developer9969

ответ

3

код не вводит в заблуждение. рамки ASP.NET Идентичность была разработана, чтобы обеспечить асинхронный интерфейс, возвращая Task и указывает на это, добавив суффикс Async к имени метода:

Task<TUser> FindByIdAsync(int userId) 

Тем не менее, основной поставщик может не иметь асинхронные методы. В этом случае вы не можете создать асинхронную реализацию, но вам все равно придется реализовать интерфейс, и для этого будет использоваться Task.FromResult точно так же, как это делается в вашем первом фрагменте кода.

Реализация асинхронного метода с использованием синхронных код

public Task<TUser> FindByIdAsync(int userId) 
{ 
    TUser result = userTable.GetUserById(userId) as TUser; 
    return Task.FromResult<TUser>(result); 
} 

Если ваш основной поставщик поддерживает асинхронные методы, которые вы должны использовать асинхра и поджидаете.

Реализация асинхронного метода с использованием асинхронного кода

public async Task<TUser> FindByIdAsync(int userId) 
{ 
    TUser result = (await userTable.GetUserByIdAsync(userId)) as TUser; 
    return result; 
} 

Обратите внимание, что Task.FromResult не используется. Task.FromResult необходим только в том случае, если у вас есть TResult, созданный синхронным кодом, и его необходимо преобразовать в Task<TResult>, требуемый асинхронным кодом.

Иногда ваш базовый провайдер может вернуть желаемый Task<TUser> без дополнительной работы. В этом случае вы можете удалить асинхронный вызов и ждать и по-прежнему предоставлять асинхронную реализацию. Это может привести к несколько более эффективный код:

public Task<TUser> FindByIdAsync(int userId) 
{ 
    Task<TUser> result = userTable.GetUserByIdAsync(userId); 
    return result; 
} 
+0

Мне нравится ваш ответ, но для меня все еще вводящим в заблуждение и сокращающим то, что они проповедуют. Если у вас есть метод «асинхронный», то вы должны вернуть реализацию async. Microsoft в своих интерфейсах была непоследовательна, поскольку они объявляют метод с «Async», но затем при реализации вы должны быть syncronus. Теперь, пожалуйста, объясните мне это. в C# у нас есть только FirstDefault, ToList и т. д. Когда вы их реализуете, вы делаете свой код синхронным? Правильно ли мое предположение?Я ненавижу EF, но у них есть FirstAndDefaultAsync и т. Д. – developer9969

+0

@ developer9969: нет ничего неправильного в создании интерфейса, который поддерживает асинхронные операции, позволяя методам возвращать 'Task '. Если вы хотите реализовать этот интерфейс, вы можете сделать это асинхронно. Если вы используете EF, вы должны использовать 'FirstOrDefatultAsync', однако, если вы используете какой-то другой механизм доступа к данным, который не поддерживает асинхронные операции, вам придется создать синхронную реализацию. Если дорога безопасна для вождения со скоростью 100 миль в час, это нормально, чтобы установить ограничение скорости со скоростью 100 миль в час, а затем решить ехать в машине, которая может идти только быстро, как 50 миль/ч. –

+0

Точка, принятая, однако, в их интерфейсе они делают «общедоступную задачу CreateAsync (пользователь T), если она не будет« общедоступной »Задача CreateAsync (T user)», чтобы вы могли полностью выполнить асинхронный процесс? Я не использую EF Я использую raw ado.net, который является самым быстрым, и у меня нет перегрузок для firstDefaultAsync, toListAsync и т. д. ... жаль. Последний вопрос, когда вы делаете «FirstOrDefault», который является синхронным. «Спасибо». Просто пытайтесь понять, что книги async/await не упоминают эти вещи – developer9969

0

Исходный код определенно не асинхронный. это выглядит как это было сделано таким образом, чтобы справиться с дизайном API.

Однако предлагаемое изменение не выглядит как асинхронно для меня. Task.FromResult просто создает завершенную задачу с результатом, не делает ничего асинхронным или выполняет любой вид ожидаемого кода, поэтому вам не стоит ждать его.

В вашем случае, если предположить, GetUserByIdAsync Возвращает Task<TUser>, и предполагая, что весь смысл этого кода (как это кажется), чтобы всегда возвращать завершенную задачу (не нарушенными или аннулированными), это может быть переписано в виде:

public async Task<TUser> FindByIdAsync(int userId) 
{ 
    var tResult = userTable.GetUserByIdAsync(userId); 
    TUser result = null; 
    try 
    { 
    result = await tResult; 
    } 
    except 
    { 
    // Bad idea, but here goes to your first snippet 
    } 
    return Task.FromResult<TUser>(result); 
} 

Примечание: это плохая идея, так как прокомментировал @PanagiotisKanavos, он скрывается, возможно, состояние поврежденной, и вы никогда не будете знать, если ваш null результат пришел пользователь не найден, или если существует условие ошибки: Я бы избегал этого.

Если неисправное/отменено состояние действительно, это может быть просто:

public Task<TUser> FindByIdAsync(int userId) 
{ 
    return userTable.GetUserByIdAsync(userId); 
} 
+1

На самом деле оба этих фрагмента являются излишними. «Try/finally» бессмысленно - он не работает, исключение будет распространяться. Если вы не разворачиваете результат, чтобы обернуть олово в Задаче. Вы также * не * должны использовать 'async/await', когда вы вызываете только асинхронные методы - просто верните задачу как есть. –

+0

@PanagiotisKanavos, это правильно, я редактировал второй отрезанный. Try/наконец-то там, чтобы сбойная задача вернулась как завершенная (что, похоже, является тем, что делает первый фрагмент в вопросе OP), а не как сбой – Jcl

+0

Нет, этого не будет, и это не должно. Исключение будет распространяться в любом случае. Что касается «скрытия» исключения, это очень плохая идея. Теперь это заставит вызывающих абонентов иметь дело с двусмысленными нулевыми значениями. Не говоря уже о том, что причина отказа будет потеряна. –

0

async метод является способом для компилятора, чтобы построить что-то, что будет возвращать обещания наших будущего . В случае .NET Framework и C# это Task.

await инструкция принимает любое awaitable и Task как раз случается быть один.Он не знает и не заботится о том, действительно ли метод/операции вызывается асинхронно или нет.

Task.FromResult<T> возвращает завершенную задачу, и если вы используете ее в инструкции await внутри метода async, это будет считаться выполненным синхронно, и выполнение будет продолжено.

Таким образом, используя async и await только с вызовами Task.FromResult<T> заканчивается просто быть тратой циклов центрального процессора и памяти компилятора генерирующего кодом, который будет тратить больше циклов процессора и память во время выполнения.

Поскольку async метод всегда возвращает Task было принято решение сделать его неявным улучшить читаемость и придать ей вид синхронизации чувства. Компиляция вернет возвращаемое значение в Task. Вот почему вы не можете напрямую вернуть Task.FromResult<TUser>(result) или Task.FromResult<TUser>(null) и ожидаете его, чтобы получить значение.

Таким образом, async эквивалент вашего синхронного кода будет:

public async Task<TUser> FindByIdAsync(int userId) 
{ 
    var result = await userTable.GetUserByIdAsync(userId) as TUser; 
    if (result != null) 
    { 
     return result; 
    } 

    return null; 
} 

Или:

public async Task<TUser> FindByIdAsync(int userId) 
{ 
    return await userTable.GetUserByIdAsync(userId) as TUser; 
} 
+0

спасибо за ваш ответ. На практическом уровне, как бы вы реорганизовали фрагмент выше? Я прочитал много документов и посоветовал, но я все еще не знаю, как правильно его закодировать – developer9969

+0

У вас есть метод userTable.GetUserByIdAsync (userId)? Или просто метод 'userTable.GetUserById (userId)'? –

+0

У меня есть userTable.GetUserByIdAsync (userId). Также, что происходит, когда вы делаете FirstOrDefault? так как я использую чистый ado.net, я не думаю, что есть firstOrDefaulAsync. Действительно ли firstOrDefault делает async бессмысленным, если так, как вы должны его преодолеть? – developer9969

Смежные вопросы