/// <summary> /// Verifies sorting entities order by ascending or descending. /// </summary> /// <param name="context">The Interop service context.</param> /// <param name="sortedType">The sorted type.</param> /// <param name="passed">Out parameter indicates validation for sort pass or not</param> /// <param name="info">Out parameter indicates the extension rule violation information.</param> /// <returns>Returns the HTTP status code of the response.</returns> public static HttpStatusCode? VerifySortEntities(ServiceContext context, SortedType sortedType, out bool? passed, out ExtensionRuleViolationInfo info) { if (SortedType.ASC == sortedType && context.ServiceVerResult.AscSortVerResult != null && context.ServiceVerResult.AscSortVerResult.Passed.HasValue) { info = context.ServiceVerResult.AscSortVerResult.ViolationInfo; passed = context.ServiceVerResult.AscSortVerResult.Passed; return context.ServiceVerResult.AscSortVerResult.ResponseStatusCode; } if (SortedType.DESC == sortedType && context.ServiceVerResult.DescSortVerResult != null && context.ServiceVerResult.DescSortVerResult.Passed.HasValue) { info = context.ServiceVerResult.DescSortVerResult.ViolationInfo; passed = context.ServiceVerResult.DescSortVerResult.Passed; return context.ServiceVerResult.DescSortVerResult.ResponseStatusCode; } passed = null; HttpStatusCode? respStatusCode = null; ExtensionRuleResultDetail detail1 = new ExtensionRuleResultDetail(); List<string> sortedPropTypes = new List<string>() { PrimitiveDataTypes.Binary, PrimitiveDataTypes.Boolean, PrimitiveDataTypes.Byte, PrimitiveDataTypes.Decimal, PrimitiveDataTypes.Double, PrimitiveDataTypes.Guid, PrimitiveDataTypes.Int16, PrimitiveDataTypes.Int32, PrimitiveDataTypes.Int64, PrimitiveDataTypes.SByte, PrimitiveDataTypes.Single, PrimitiveDataTypes.String }; var restrictions = AnnotationsHelper.GetFilterRestrictions(context.MetadataDocument, context.VocCapabilities, sortedPropTypes); if (string.IsNullOrEmpty(restrictions.Item1) || null == restrictions.Item2 || !restrictions.Item2.Any()) { detail1.ErrorMessage = "Cannot find any appropriate entity-sets which support system query options $filter in the service."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1); } string entitySet = restrictions.Item1; string sortedPropName = restrictions.Item2.First().PropertyName; string sortedPropType = restrictions.Item2.First().PropertyType; string url = string.Format("{0}/{1}?$orderby={2} {3}", context.ServiceBaseUri, entitySet, sortedPropName, sortedType.ToString().ToLower()); var resp = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); detail1 = new ExtensionRuleResultDetail(string.Empty, url, "GET", StringHelper.MergeHeaders(Constants.AcceptHeaderJson, context.RequestHeaders), resp); if (resp != null && resp.StatusCode == HttpStatusCode.OK) { JObject feed; resp.ResponsePayload.TryToJObject(out feed); if (feed == null || VerifySortedEntitiesSequence(feed, sortedPropName, sortedPropType, sortedType) != true) { passed = false; detail1.ErrorMessage = string.Format("The service does not execute an accurate result on the system query option $orderby {0} on individual properties.", sortedType == SortedType.ASC ? "asc" : "desc"); } else { passed = true; } } else { passed = false; detail1.ErrorMessage = "The service does not support the system query option '$orderby'."; } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1); respStatusCode = resp != null ? resp.StatusCode : null; if (SortedType.ASC == sortedType) { context.ServiceVerResult.AscSortVerResult = new ServiceVerificationResult(passed, info, respStatusCode); } else if (SortedType.DESC == sortedType) { context.ServiceVerResult.DescSortVerResult = new ServiceVerificationResult(passed, info, respStatusCode); } return respStatusCode; }
/// <summary> /// Verifies sorting entities order by ascending or descending. /// </summary> /// <param name="context">The Interop service context.</param> /// <param name="sortedType">The sorted type.</param> /// <param name="info">Out parameter indicates the extension rule violation information.</param> /// <returns>True: The sort validation pass; false: otherwise</returns> public static bool? VerifySortEntities( ServiceContext context, SortedType sortedType, out ExtensionRuleViolationInfo info) { List<JToken> entities1 = null; List<JToken> entities2 = new List<JToken>(); ExtensionRuleResultDetail detail1 = new ExtensionRuleResultDetail(); string entitySet = string.Empty; string navigPropName = string.Empty; string sortedPropName = string.Empty; string sortedPropType = string.Empty; var restrictions = new Dictionary<string, Tuple<List<NormalProperty>, List<NavigProperty>>>(); if (!AnnotationsHelper.GetExpandRestrictions(context.MetadataDocument, context.VocCapabilities, ref restrictions)) { detail1.ErrorMessage = "Cannot find any appropriate entity-sets which support system query options $expand in the service."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1); return null; } foreach (var r in restrictions) { if (string.IsNullOrEmpty(r.Key) || null == r.Value.Item1 || !r.Value.Item1.Any() || null == r.Value.Item2 || !r.Value.Item2.Any()) { continue; } bool flag = false; foreach (var np in r.Value.Item2) { if (NavigationRoughType.CollectionValued == np.NavigationRoughType) { var nEntityTypeShortName = np.NavigationPropertyType.RemoveCollectionFlag().GetLastSegment(); var nEntitySetName = nEntityTypeShortName.MapEntityTypeShortNameToEntitySetName(); var funcs = new List<Func<string, string, string, List<NormalProperty>, List<NavigProperty>, bool>>() { AnnotationsHelper.GetFilterRestrictions }; List<string> sortedPropTypes = new List<string>() { PrimitiveDataTypes.Binary, PrimitiveDataTypes.Boolean, PrimitiveDataTypes.Byte, PrimitiveDataTypes.Decimal, PrimitiveDataTypes.Double, PrimitiveDataTypes.Guid, PrimitiveDataTypes.Int16, PrimitiveDataTypes.Int32, PrimitiveDataTypes.Int64, PrimitiveDataTypes.SByte, PrimitiveDataTypes.Single, PrimitiveDataTypes.String }; var filterRestrictions = nEntitySetName.GetRestrictions(context.MetadataDocument, context.VocCapabilities, funcs, sortedPropTypes); if (!string.IsNullOrEmpty(filterRestrictions.Item1) || null != filterRestrictions.Item2 || filterRestrictions.Item2.Any() || null != filterRestrictions.Item3 || filterRestrictions.Item3.Any()) { flag = true; entitySet = r.Key; navigPropName = np.NavigationPropertyName; sortedPropName = filterRestrictions.Item2.First().PropertyName; sortedPropType = filterRestrictions.Item2.First().PropertyType; break; } } } if (flag) { break; } } if (string.IsNullOrEmpty(sortedPropName) || string.IsNullOrEmpty(sortedPropType) || string.IsNullOrEmpty(entitySet) || string.IsNullOrEmpty(navigPropName)) { detail1.ErrorMessage = "Cannot find an appropriate entity-set to verify the system query option $orderby.\r\n"; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1); return null; } string url = string.Format("{0}/{1}?$expand={2}($orderby={3} {4})", context.ServiceBaseUri, entitySet, navigPropName, sortedPropName, sortedType.ToString().ToLower()); Uri uri = new Uri(url); Response resp = WebHelper.Get(uri, Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); detail1 = new ExtensionRuleResultDetail("", uri.AbsoluteUri, "GET", StringHelper.MergeHeaders(Constants.AcceptHeaderJson, context.RequestHeaders), resp); if (resp != null && resp.StatusCode == HttpStatusCode.OK) { JObject feed; resp.ResponsePayload.TryToJObject(out feed); var entities = JsonParserHelper.GetEntries(feed); if (null == entities) { detail1.ErrorMessage = string.Format("The entity-set '{0}' has no entity in the service.", entitySet); info = new ExtensionRuleViolationInfo(uri, resp.ResponsePayload, detail1); return null; } foreach (var en in entities) { if (null != en[navigPropName] && JTokenType.Array == en[navigPropName].Type) { entities1 = en[navigPropName].ToList(); break; } } entities2.AddRange(entities1); entities2.Sort(new JTokenCompare(sortedPropName, sortedPropType, sortedType)); } else { detail1.ErrorMessage = "The service does not support the system query option '$orderby'."; info = new ExtensionRuleViolationInfo(uri, resp.ResponsePayload, detail1); return false; } bool? result = entities1.SequenceEquals(entities2); if (result == false) { detail1.ErrorMessage = string.Format("The service does not support $orderby ({0}) system query options.", sortedType.ToString().ToLower()); } info = new ExtensionRuleViolationInfo(uri, resp.ResponsePayload, detail1); return result; }