2016-03-12 7 views
0

У меня есть небольшое приложение MVC 5, которое вызывает веб-службу и получает ответ JSON. Я десериализую ответ в свой собственный тип, и он передается в представление, и данные отображаются бритвой.Async JSON deserialisation в ASP.NET

Обработчик контроллер:

public async Task<ActionResult> Search(string q) 
    { 
     var vm = new SearchResultViewModel(await _searchService.GetDataAsync(q)); 
     return View(vm); 
    } 

Метод поиска услуг:

public async Task<ISearchResult> GetDataAsync(string q) 
    { 
     var fullRequest = new UriBuilder(RequestUri) {Query = "q=" + q}; 

     var result = await _client.GetAsync(fullRequest.ToString()).ConfigureAwait(false); 

     if (result.IsSuccessStatusCode) 
     { 
      var jsonResponse = await result.Content.ReadAsStringAsync().ConfigureAwait(false); 

      // How should I call this? 
      return JsonConvert.DeserializeObject<SearchResult>(jsonResponse); 
     } 
     return new SearchResult 
    } 

Мой вопрос: Как я должен позвонить JsonConvert.DeserializeObject? Это операция с привязкой к процессору, так что нормально звонить синхронно (и блокировать поток), так как я не могу вернуться, пока это не будет выполнено? Если есть проблема с десериализацией, токен отмены не может быть использован.

Если я должен позвонить асинхронно, следует ли использовать Task.Factory.StartNew(), как предложено intellisense, в качестве замены устаревшего JsonConvert.DeserializeObjectAsync()? This Канал 9 видео предлагает (на 58 минут), что это не такая хорошая идея. Возможно, другой вариант, например Task.Run()? Возможно, это плохая идея, поскольку это может вызвать проблемы с SyncContext?

Любые указатели с благодарностью получили!

+1

Я не думаю, что существует разница между 'Task.Factory.StartNew()' и 'Task.Run()', за исключением случаев, когда вы не хотите использовать threadpool. Я бы сказал, что ваш код в порядке, как есть (например, десериализовать синхронно), если JSON не будет большим, и в этом случае вы могли бы делать буферизованные данные, считанные из вашего результата result.Content как поток (если возможно) и десериализовать JSON в потоковом режиме, а не сначала выделять всю строку. – jamespconnor

+1

@SimonB: Для справок в будущем не используйте 'Task.Factory.StartNew'; он имеет опасные значения по умолчанию. 'Task.Run' безопаснее. Однако в большинстве случаев ни один из них не должен использоваться на ASP.NET. –

+0

@ StephenCleary Спасибо за головы! Я не уверен, какие варианты использования для ASP.NET, особенно для процессоров, связанных с операциями. Возможно, если у вас есть несколько параллельных задач? Очевидно, что высокий параллелизм имеет свои проблемы в контексте веб-сервера. –

ответ

3

Ваш код хорош как есть. DeserializeObject будет запускаться внутри потока ниток, поскольку вы используете ConfigureAwait(false).

Ваш общий метод (GetDataAsync) все равно будет асинхронным, так как он вернется к вызывающему абоненту по первому await.

+1

Замечание: вопрос, поставленный с помощью ASP.Net, где использование 'ConfigureAwait (false)' не делает ничего хорошего (использование, как правило, коммандерного программирования). Он также активно вреден, если код после вызова асинхронного доступа требует доступа к запросу или текущей культуре (см. Http://stackoverflow.com/questions/13489065/best-practice-to-call-configureawait-for-all-server-side-code для долгого обсуждения) –

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