/// <summary> /// Add a request for a set of entities and queries. /// </summary> /// <param name="batch">The batch.</param> /// <param name="hintText">A hint about what this query is doing. Use for logging/diagnostics only.</param> /// <exception cref="System.ArgumentException"> /// </exception> /// <exception cref="System.Exception">Internal error: batch query mismatch.</exception> public void AddEntityRequestBatch(JsonQueryBatchRequest batch, string hintText = null) { JsonQueryResult result = _result; #pragma warning disable 618 EntityInfoService svc = _svc; #pragma warning restore 618 var memberRequests = new EntityMemberRequest[batch.Queries.Length]; foreach (JsonQuerySingleRequest request in batch.Requests) { string requestHintText = request.Hint ?? hintText; _entitiesVisited.Clear( ); var singleResult = new JsonSingleQueryResult { Hint = request.Hint, Ids = new List <long>( ) }; try { EntityMemberRequest memberRequest; // Do not require access to the individual query components using (PerformanceCounters.Measure(EntityInfoServicePerformanceCounters.CategoryName, EntityInfoServicePerformanceCounters.RequestCountersPrefix)) using (new SecurityBypassContext( )) { // Get/parse the request query. (Either parse, or load from previous cache as part of this request). if (request.QueryIndex < 0 || request.QueryIndex >= batch.Queries.Length) { EventLog.Application.WriteError("Cannot locate query string."); singleResult.Code = HttpStatusCode.BadRequest; continue; } memberRequest = memberRequests[request.QueryIndex]; if (memberRequest == null) { string queryString = batch.Queries[request.QueryIndex]; //// Parse the request try { memberRequest = Factory.RequestParser.ParseRequestQuery(queryString); } catch (Exception ex) { EventLog.Application.WriteError(ex.ToString( )); singleResult.Code = HttpStatusCode.BadRequest; continue; } memberRequests[request.QueryIndex] = memberRequest; } } // Get the entityRefs IEnumerable <EntityRef> ids = Enumerable.Empty <EntityRef>( ); if (request.Aliases != null && request.Aliases.Length > 0) { ids = ids.Union(request.Aliases.Select(ConvertId)); } if (request.Ids != null && request.Ids.Length > 0) { ids = ids.Union(request.Ids.Select(ConvertId)); } IList <EntityRef> entityRefs = ids.ToList( ); if (entityRefs.All(er => er == null)) { singleResult.Code = HttpStatusCode.NotFound; continue; } // Run the request IEnumerable <EntityData> entitiesData; try { if (BulkRequestHelper.IsValidForBulkRequest(memberRequest)) { var entityRequest = new EntityRequest { QueryType = request.QueryType, RequestString = memberRequest.RequestString, Hint = requestHintText, Entities = entityRefs, Filter = request.Filter, Isolated = request.Isolated }; // Run the request entitiesData = BulkRequestRunner.GetEntities(entityRequest); singleResult.Cached = entityRequest.ResultFromCache; } else { EventLog.Application.WriteWarning( "Request cannot be handled by BulkRequest. Hint: {0}\n{1}", requestHintText, memberRequest.RequestString); switch (request.QueryType) { case QueryType.Instances: entitiesData = svc.GetEntitiesByType(entityRefs.Single( ), true, memberRequest); break; case QueryType.ExactInstances: entitiesData = svc.GetEntitiesByType(entityRefs.Single( ), false, memberRequest); break; case QueryType.Basic: case QueryType.BasicWithDemand: entitiesData = svc.GetEntitiesData(entityRefs, memberRequest); break; default: throw new ArgumentException(string.Format("Unknown query type {0}", request.QueryType)); } } } catch (ArgumentException ex) { // sorry world! if (ex.Message.Contains("does not represent a known entity")) { singleResult.Code = HttpStatusCode.BadRequest; continue; } throw; } // Skip results where access is denied foreach (EntityData entityData in entitiesData.Where(ed => ed != null)) { AppendEntityToResult(result, entityData); singleResult.Ids.Add(entityData.Id.Id); } // Set the result to NotFound for Basic and BasicWithDemand only if (request.QueryType == QueryType.Basic || request.QueryType == QueryType.BasicWithDemand) { singleResult.Code = singleResult.Ids.Count > 0 ? HttpStatusCode.OK : HttpStatusCode.NotFound; } else { singleResult.Code = HttpStatusCode.OK; } } catch (PlatformSecurityException ex) { EventLog.Application.WriteWarning(ex.ToString( )); singleResult.Ids.Clear( ); singleResult.Code = HttpStatusCode.Forbidden; } catch (Exception ex) { EventLog.Application.WriteError(ex.ToString( )); singleResult.Code = HttpStatusCode.InternalServerError; } finally { // Place in the finally block so we are certain that it gets run exactly once per iteration result.Results.Add(singleResult); } } if (result.Results.Count != batch.Requests.Length) { // We are indexing by ID, so we must always ensure that request position matches result position. throw new Exception("Internal error: batch query mismatch."); } }
/// <summary> /// Add a request for a set of entities and queries. /// </summary> /// <param name="batch"></param> public void AddEntityRequestBatch(JsonQueryBatchRequest batch) { var result = this.Result; var svc = Svc; var memberRequests = new EntityMemberRequest[batch.Queries.Length]; foreach (var request in batch.Requests) { EntitiesVisited.Clear(); var singleResult = new JsonSingleQueryResult(); try { // Get/parse the request query. (Either parse, or load from previous cache as part of this request). if (request.QueryIndex < 0 || request.QueryIndex >= batch.Queries.Length) { throw new Exception("Cannot locate query string."); } var memberRequest = memberRequests[request.QueryIndex]; if (memberRequest == null) { string queryString = batch.Queries[request.QueryIndex]; //// Parse the request try { memberRequest = EntityRequestHelper.BuildRequest(queryString); } catch (Exception ex) { EventLog.Application.WriteError(ex.ToString()); singleResult.Code = HttpStatusCode.BadRequest; continue; } memberRequests[request.QueryIndex] = memberRequest; } // Get the entityRefs IEnumerable <EntityRef> entityRefs = request.Ids.Select(objId => { if (objId is string) { var entityRef = new EntityRef((string)objId); try { long id = entityRef.Id; } catch (ArgumentException ex) { singleResult.Code = HttpStatusCode.NotFound; return(new EntityRef(0)); // or whatever } return(entityRef); } if (objId is long) { return(new EntityRef((long)objId)); } if (objId is int) { return(new EntityRef((long)(int)objId)); } throw new InvalidOperationException(); }); // Run the request IEnumerable <EntityData> entitiesData; try { switch (request.QueryType) { case QueryType.Instances: entitiesData = svc.GetEntitiesByType(entityRefs.Single(), true, memberRequest); break; case QueryType.ExactInstances: entitiesData = svc.GetEntitiesByType(entityRefs.Single(), false, memberRequest); break; case QueryType.Basic: default: entitiesData = svc.GetEntitiesData(entityRefs, memberRequest); break; } } catch (ArgumentException ex) { // sorry world! if (ex.Message.Contains("does not represent a known entity")) { singleResult.Code = HttpStatusCode.BadRequest; continue; } throw; } // Package results singleResult.IDs = new List <long>(); foreach (var entityData in entitiesData) { AppendEntityToResult(result, entityData, this); singleResult.IDs.Add(entityData.Id.Id); } // Capture result code singleResult.Code = singleResult.IDs.Count > 0 ? HttpStatusCode.OK : HttpStatusCode.NotFound; } catch (Exception ex) { EventLog.Application.WriteError(ex.ToString()); singleResult.Code = HttpStatusCode.InternalServerError; } finally { // Place in the finally block so we are certain that it gets run exactly once per iteration result.Results.Add(singleResult); } } if (result.Results.Count != batch.Requests.Length) { // We are indexing by ID, so we must always ensure that request position matches result position. throw new Exception("Internal error: batch query mismatch."); } }