2016-04-06 3 views
2

Дано:Почему эта оболочка для синхронизации по асинхронному методу работает?

  • Наследство не Асинхр метод API на веб-службы ASP.NET/WCF
  • Новая асинхронная внутренняя библиотека
  • Новый контроллер асинхронной Web API, который должен использоваться в будущем
  • Объект «поставщик хранилища», который имеет только асинхронный интерфейс. Его тесты проходят при запуске асинхронно и при синхронном запуске вне контекста запроса.

Опция «go async all the way» не находится на столе, так как она нарушила бы обратную совместимость.

public class Impl { 
    // This works fine when used asynchronously 
    public Task<Guid> SaveThingAsync(Thing thingToSave) { 
     return await _storageProvider.saveAsync(thingToSave); 
    } 

    public Guid SaveThing(Thing thingToSave) { 
     // "Obviously", this code creates a deadlock when called 
     // from within the request context 
     // return SaveThingAsync(thingToSave).Result 

     // Not so obviously, this also creates a deadlock 
     // return SaveThingAsync(thingToSave) 
     //   .ConfigureAwait(false) 
     //   .GetAwaiter() 
     //   .GetResult() 

     // This was deadlocking, but magically stopped 
     // return Task.Run(
     //  async() => await SaveThingAsync(thingToSave) 
     //      .ConfigureAwait(false) 
     //    ).Result; 

     // This one works 
     var saveTask = Task.Run(async() => 
          await SaveThingAsync(thingToSave))); 
     var result = saveTask.ConfigureAwait(false).GetAwaiter().GetResult(); 
     return result; 
    } 

Почему?

ответ

1

Task.Run шаги «снаружи» контекста запроса - он просто запускается в контексте пула потоков. Таким образом, он не будет блокироваться, потому что SaveThingAsync не возобновляется в контексте запроса.

На боковой ноте ConfigureAwait(false) не имеет смысла там, так как нет await для настройки.

С другой стороны, «асинхронный путь» все равно должен быть вариантом. Клиенты WebAPI и WCF все равно, является ли реализация, которую они вызывают, синхронной или асинхронной. Изменение метода WCF, реализованного синхронно с методом WCF, реализованным асинхронно, невидимо для клиентского кода.

+0

Ну, это раздражает. Вчера я получал исключение TaskCancelled при запуске первого примера «Task.Run». Поскольку наши клиенты не просто используют ссылку на прямую службу, но вместо этого клиентскую библиотеку, созданную на наших интерфейсах, изменение интерфейса SOAP приведет к сломанию всего. – Eris

+0

@ Эрис клиент не может сказать, как сказал Стивен. Это не проблема совместимости. Это объясняется здесь: http://stackoverflow.com/a/22591516/122718 – usr

+0

@Eris: Первый (прокомментированный) пример 'Task.Run' действительно, * действительно * странный. Он изгибает мой мозг, пытаясь понять, что он будет делать. Прохождение структур 'ConfiguredTaskAwaitable' не является идиоматическим. Вы должны иметь возможность использовать свой собственный (асинхронный) интерфейс на сервере вместо синхронного интерфейса, потребляемого клиентами - к сожалению, это (логически) дублирует описание интерфейса. –

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