/// <summary> /// Executes a <see cref="IFtsQuery" /> request including any <see cref="ISearchParams" /> parameters asynchronously. /// </summary> /// <returns>A <see cref="ISearchQueryResult"/> wrapped in a <see cref="Task"/> for awaiting on.</returns> public async Task <ISearchQueryResult> QueryAsync(SearchQuery searchQuery, CancellationToken cancellationToken) { var searchResult = new SearchQueryResult(); var baseUri = Context.GetSearchUri(); var requestUri = new Uri(baseUri, searchQuery.RelativeUri()); string searchBody; using (ClientConfiguration.Tracer.BuildSpan(searchQuery, CouchbaseOperationNames.RequestEncoding).StartActive()) { searchBody = searchQuery.ToJson(); } try { using (var content = new StringContent(searchBody, Encoding.UTF8, MediaType.Json)) { HttpResponseMessage response; using (ClientConfiguration.Tracer.BuildSpan(searchQuery, CouchbaseOperationNames.DispatchToServer).StartActive()) { response = await HttpClient.PostAsync(requestUri, content, cancellationToken).ContinueOnAnyContext(); } using (ClientConfiguration.Tracer.BuildSpan(searchQuery, CouchbaseOperationNames.ResponseDecoding).StartActive()) using (var stream = await response.Content.ReadAsStreamAsync().ContinueOnAnyContext()) { if (response.IsSuccessStatusCode) { searchResult = DataMapper.Map <SearchQueryResult>(stream); } else { string responseContent; using (var reader = new StreamReader(stream)) { responseContent = await reader.ReadToEndAsync().ContinueOnAnyContext(); } if (response.Content.Headers.TryGetValues("Content-Type", out var values) && values.Any(value => value.Contains(MediaType.Json))) { // server 5.5+ responds with JSON content var result = JsonConvert.DeserializeObject <FailedSearchQueryResult>(responseContent); ProcessError(new HttpRequestException(result.Message), searchResult); searchResult.Errors.Add(result.Message); } else { // use response content as raw string // ReSharper disable once UseStringInterpolation var message = string.Format("{0}: {1}", (int)response.StatusCode, response.ReasonPhrase); ProcessError(new HttpRequestException(message), searchResult); searchResult.Errors.Add(responseContent); } if (response.StatusCode == HttpStatusCode.NotFound) { baseUri.IncrementFailed(); } } } } baseUri.ClearFailed(); } catch (OperationCanceledException e) { var operationContext = OperationContext.CreateSearchContext(Context.BucketName, baseUri?.Authority); if (searchQuery is SearchQuery query) { operationContext.TimeoutMicroseconds = query.TimeoutValue; } Log.Info(operationContext.ToString()); ProcessError(e, searchResult); } catch (HttpRequestException e) { Log.Info("Search failed {0}: {1}{2}", baseUri, Environment.NewLine, User(searchBody)); baseUri.IncrementFailed(); ProcessError(e, searchResult); Log.Error(e); } catch (AggregateException ae) { ae.Flatten().Handle(e => { Log.Info("Search failed {0}: {1}{2}", baseUri, Environment.NewLine, User(searchBody)); ProcessError(e, searchResult); return(true); }); } catch (Exception e) { Log.Info("Search failed {0}: {1}{2}", baseUri, Environment.NewLine, User(searchBody)); Log.Info(e); ProcessError(e, searchResult); } UpdateLastActivity(); return(searchResult); }