private async Task <IHttpActionResult> InternalSearch(LibraryIndexHelper.IndexKinds indexKind, int offset, int limit, string categoryId = null, string q = null) { if (limit > AzureSearchHelper.SearchResults_MaxLimit) { throw new ArgumentException(String.Format("Search results limit is {0}.", AzureSearchHelper.SearchResults_MaxLimit)); } var isPersonal = indexKind == LibraryIndexHelper.IndexKinds.PersonalCollection; var userId = this.GetUserId(); // Find resources in Azure Search. var search = new AzureSearchHelper(indexKind, isPersonal ? userId : 0); var resultsJson = await search.Search(offset, limit, categoryId, q); if (isPersonal || (userId == 0)) { return(new RawStringResult(this, resultsJson, RawStringResult.TextMediaType.Json)); } else { // Common collection for an authorized user. Augment the results with personal data from database. var results = JsonConvert.DeserializeObject <AzureSearchResults>(resultsJson); if (results.Value.Any()) { var resourcesXml = new XElement("Resources", results.Value.Select(i => new XElement("R", new XAttribute("Id", i.Id))) ) .ToString(SaveOptions.DisableFormatting); const string sql = @" select Id, IsPersonal, LanguageLevelRating, Comment from dbo.libGetUserResources (@UserId, @Resources); "; var views = await DapperHelper.QueryResilientlyAsync <ResourceDto>(sql, new { UserId = userId, Resources = resourcesXml }); // Copy personalization values from the items we got from the database to the resources we got from search. var resourceDict = results.Value.ToDictionary(i => i.Id); foreach (var v in views) { // We expect the Ids returned from the database correspond to the Ids provided as arguments in XML. Otherwise a horrible KeyNotFoundException will ruine everything. var r = resourceDict[v.Id]; // We do not store the Viewed value explicitly in the database. IsPersonal is not nullable. So the mere presense of an IsPersonal in a record means the resource has been viewed. r.IsPersonal = v.IsPersonal; r.LanguageLevelRating = v.LanguageLevelRating; r.Comment = v.Comment; r.Viewed = true; } } // Since we send original raw Azure Search results in the "Personal" case as is, we use here Ok<AzureSearchResults> as well to substitute names from attributes for member names, i.e. "@odata.count" and "value". return(Ok <AzureSearchResults>(results)); } }
public AzureSearchHelper(LibraryIndexHelper.IndexKinds indexKind, int userId = 0) : this(LibraryIndexHelper.GetIndexName(indexKind), userId) { }