/// <summary> /// Verify the rule /// </summary> /// <param name="context">Service context</param> /// <param name="info">out paramater to return violation information when rule fail</param> /// <returns>true if rule passes; false otherwise</returns> public override bool?Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool?passed = null; info = null; var qs = HttpUtility.ParseQueryString(context.Destination.Query); string qExpand = qs["$expand"]; if (!string.IsNullOrEmpty(qExpand)) { var edmxHelper = new EdmxHelper(XElement.Parse(context.MetadataDocument)); EntityType et; edmxHelper.TryGetItem(context.EntityTypeFullName, out et); var branches = ResourcePathHelper.GetBranchedSegments(qExpand); foreach (var paths in branches) { var navStack = ODataUriAnalyzer.GetNavigationStack(et, paths).ToArray(); bool[] targetIsCollection = (from n in navStack select n.RelationshipMultiplicity == RelationshipMultiplicity.Many).ToArray(); // to check each entity set resolved along the navigation path to have proper structure (json array, each item has proper properties) TestResult result = null; JObject jo = JObject.Parse(context.ResponsePayload); var version = JsonParserHelper.GetPayloadODataVersion(jo); for (int i = 0; i < paths.Length; i++) { string jSchema = null; if (navStack[i].RelationshipMultiplicity == RelationshipMultiplicity.Many) { var etShort = navStack[i].GetEntityType().FullName.GetLastSegment(); string jsET = JsonSchemaHelper.GetSchemaForEntityType(etShort, context.MetadataDocument); string jsCore = string.Format(@"""{0}"": {{""type"": ""array"", ""required"" : true, ""items"": {1} }}", paths[i], jsET); jSchema = JsonSchemaHelper.GetJsonSchema(paths, i, version, jsCore, targetIsCollection); passed = JsonParserHelper.ValidateJson(jSchema, context.ResponsePayload, out result); if (!passed.Value) { break; } } } if (!passed.Value) { info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload, result != null ? result.LineNumberInError : -1); break; } } } return(passed); }