2016-06-06 5 views
1

Я получаю мои ноги мокрыми, используя async/await, и большинство из того, что я читал, состояния «Не блокировать асинхронный код», за исключением основной функции в консольном приложении. Я не могу следовать этому простому правилу :(Как обращаться с вызовами асинхронного API с помощью CMS, который не позволяет выполнять действия контроллера Async?

Мое приложение сильно зависит от уровня WebAPI. Клиент, который я использую в приложении MVC, использует методы async на System.Net.Http.HttpClient, чтобы вызвать методы API. В настоящее время я обрабатываю его два пути в некоторых местах мы сразу же получать результат после вызова клиента:..

//WebAPI Client 
public object GetSomething(int id) 
{ 
    var task = _client_GetSomethingFromApiAsync(id); 
    var result = task.Result; 
    return result; 
} 

в других, используя асинхронную весь путь до контроллера я использую SiteFinity и не могу использовать асинхронное действие контроллера, так что я в конечном итоге с чем-то вроде этого:

//WebAPI Client 
public Task<object> GetSomethingAsync(int id) 
{ 
    return _client_GetSomethingFromApiAsync(id);  
} 

//Domain Service 
public Task<object> GetSomethingDomainServiceAsync(int id) 
{ 
    return _service.GetSomethingAsync(id); 
} 

//Controller 
public JsonResult GetSomethingControllerAction(int id) 
{ 
    var result = _domainService.GetSomethingDomainServiceAsync(viewModel.id).Result; 
    return Json(new { Success = true, Payload = result }); 
} 

Основываясь на моем исследовании, оба этих решения не идеальны, хотя у меня не было никаких проблем с взаимоблокировками, и все, кажется, работает. Может кто-то, пожалуйста, помогите мне понять лучший образец, за которым я должен следовать и объяснить почему?

Спасибо!

ответ

2

Я использую SiteFinity и не могу использовать асинхронное действие контроллера

According to SiteFinity, он поддерживает асинхронное действие контроллера, просто не ASync действия в виджетах. Если это ваша ситуация, я рекомендую вам vote.

Предполагая, что вы находитесь в этой ситуации - и не можете использовать код async - тогда я рекомендую вам всего лишь использовать синхронный код. То есть, замените, HttpClient на WebClient или что-то в этом роде. Я не рекомендую использовать Result, так как это возможно (маловероятно, но возможно), что будущие обновления до HttpClient могут вызывать взаимоблокировки, даже если ваш код сегодня не блокируется.

Если вы не хотите терять инвестиции, которые вы уже сделали в async, тогда я бы рекомендовал использовать «логический аргумент», как описано в моей статье на brownfield async.

+0

Большая статья, спасибо! – Mike

+0

Решил добавить как асинхронные, так и синхронные методы к моему клиенту API. Например, GetAsync будет использовать HttpClient, а Get будет использовать WebClient. – Mike

0

Как я понимаю, действие асинхронного контроллера просто сохраняет поток. Это не влияет на поведение веб-сайта.

Таким образом, без асинхронных контроллеров вам придется подождать, пока задача не будет выполнена (блокировка потока, поэтому он не может использоваться для другого запроса).

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

1

Вы не должны просто звонить Result по методу async, так как вы можете вызвать взаимоблокировки в своем приложении. Я не использую SiteFinity, но активно использую дочерние действия в MVC, а также не разрешают асинхронные ответы. Мой курс действий состоял в том, чтобы использовать вспомогательный класс, который я украл из базы данных Entity Framework.

В Entity Framework 6 добавлены методы асинхронной генерации в дополнение к исходным методам синхронизации, но за кулисами только методы async выполняют любую фактическую работу.Теперь методы синхронизации просто вызывают синхронные асинхронные методы. Для этого они реализовали внутренний вспомогательный класс под названием AsyncHelper (внутренняя видимость, поэтому вы не можете просто использовать его в своем приложении). Тем не менее, я взял код и создал свой собственный AsyncHelper в моем приложении:

public static class AsyncHelper 
{ 
    private static readonly TaskFactory _myTaskFactory = new 
     TaskFactory(CancellationToken.None, 
        TaskCreationOptions.None, 
        TaskContinuationOptions.None, 
        TaskScheduler.Default); 

    public static TResult RunSync<TResult>(Func<Task<TResult>> func) 
    { 
     return AsyncHelper._myTaskFactory 
      .StartNew<Task<TResult>>(func) 
      .Unwrap<TResult>() 
      .GetAwaiter() 
      .GetResult(); 
    } 

    public static void RunSync(Func<Task> func) 
    { 
     AsyncHelper._myTaskFactory 
      .StartNew<Task>(func) 
      .Unwrap() 
      .GetAwaiter() 
      .GetResult(); 
    } 
} 

Чтобы использовать эту функцию, в своем действии контроллера, вы бы просто сделать:

var something = AsyncHelper.RunSync<SomeType>(() => _client_GetSomethingFromApiAsync(id)); 
Смежные вопросы