/// <summary> /// Verifies the service implementation feature. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if the service implementation feature 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 svcStatus = ServiceStatus.GetInstance(); string navigPropName = string.Empty; string entityTypeShortName; var entityTypeShortNames = new List <string>(); Tuple <string, string> keyProp = null; ExtensionRuleResultDetail detailglobal = new ExtensionRuleResultDetail(this.Name); info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detailglobal); detailglobal = info.Details[0]; do { var navigPropNames = MetadataHelper.GetNavigationPropertyNames(out entityTypeShortName, entityTypeShortNames); if (null == navigPropNames || !navigPropNames.Any()) { detailglobal.ErrorMessage = "No navigation properties available to test"; return(passed); } navigPropName = navigPropNames[0]; entityTypeShortNames.Add(entityTypeShortName); keyProp = MetadataHelper.GetKeyProperty(entityTypeShortName); }while (null == keyProp); string keyPropName = keyProp.Item1; string keyPropType = keyProp.Item2; var entitySetUrl = entityTypeShortName.GetAccessEntitySetURL(); if (string.IsNullOrEmpty(entitySetUrl)) { detailglobal.ErrorMessage = "Unable to get a proper Entity URL"; return(passed); } string url = svcStatus.RootURL.TrimEnd('/') + "/" + entitySetUrl; var resp = WebHelper.Get(new Uri(url), string.Empty, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, svcStatus.DefaultHeaders); if (null == resp || HttpStatusCode.OK != resp.StatusCode) { detailglobal.ErrorMessage = resp.StatusCode + "status code returned for " + url; return(passed); } var entities = JsonParserHelper.GetEntities(resp.ResponsePayload); if (!entities.Any()) { detailglobal.ErrorMessage = "No entities returned: " + resp.ResponsePayload; return(passed); } var entity = entities.First(); if (!entity[keyPropName].HasValues) { detailglobal.ErrorMessage = keyPropName + " have no values to test"; return(passed); } string keyPropVal = entity[keyPropName].ToString(); string pattern = "Edm.String" == keyPropType ? "{0}('{1}')/{2}/$ref" : "{0}({1})/{2}/$ref"; url = string.Format(pattern, url, keyPropVal, navigPropName); resp = WebHelper.Get(new Uri(url), string.Empty, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, svcStatus.DefaultHeaders); var detail = new ExtensionRuleResultDetail("ServiceImpl_SystemQueryOptionRef", url, HttpMethod.Get, string.Empty); detail.URI = url; detail.ResponsePayload = resp.ResponsePayload; detail.ResponseHeaders = resp.ResponseHeaders; detail.HTTPMethod = "GET"; detail.ResponseStatusCode = resp.StatusCode.ToString(); info = new ExtensionRuleViolationInfo(new Uri(url), string.Empty, detailglobal); info.AddDetail(detail); if (null != resp && HttpStatusCode.OK == resp.StatusCode) { entities = JsonParserHelper.GetEntities(resp.ResponsePayload); if (!entities.Any()) { detail.ErrorMessage = "No entities available to test"; return(false); } entity = entities.First(); var odataId = entity[Constants.V4OdataId].ToString(); resp = WebHelper.Get(new Uri(url), string.Empty, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, svcStatus.DefaultHeaders); passed = null != resp && HttpStatusCode.OK == resp.StatusCode; if (passed == false) { detail.URI = url; detail.ResponsePayload = resp.ResponsePayload; detail.ResponseHeaders = resp.ResponseHeaders; detail.HTTPMethod = "GET"; detail.ResponseStatusCode = resp.StatusCode.ToString(); detail.ErrorMessage = "Response return an error message: " + resp.StatusCode.ToString(); } } else { detail.URI = url; detail.ResponsePayload = resp.ResponsePayload; detail.ResponseHeaders = resp.ResponseHeaders; detail.HTTPMethod = "GET"; detail.ResponseStatusCode = resp.StatusCode.ToString(); detail.ErrorMessage = "Response return an error message: " + resp.StatusCode.ToString(); passed = false; } return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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; ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name); var countRestrictions = AnnotationsHelper.GetCountRestrictions(context.MetadataDocument, context.VocCapabilities); if (string.IsNullOrEmpty(countRestrictions.Item1)) { detail.ErrorMessage = "Cannot find an entity-set which supports $count system query options."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } string entitySet = countRestrictions.Item1; bool isNextLinkPropExist = false; Int64 totalCount = 0; string url = string.Format("{0}/{1}?$count=true", context.ServiceBaseUri.AbsoluteUri.TrimEnd('/'), entitySet); Response resp = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); detail = new ExtensionRuleResultDetail(this.Name, url, "GET", StringHelper.MergeHeaders(Constants.V4AcceptHeaderJsonFullMetadata, context.RequestHeaders), resp); if (resp.StatusCode.HasValue && resp.StatusCode == HttpStatusCode.OK) { JObject feed; resp.ResponsePayload.TryToJObject(out feed); var entries = JsonParserHelper.GetEntries(feed); if (feed[Constants.V4OdataCount] != null) { totalCount = Convert.ToInt64(feed[Constants.V4OdataCount].Value <string>().StripOffDoubleQuotes()); if (entries.Count == totalCount) { passed = true; } else if (entries.Count < totalCount) { var jProps = feed.Children(); foreach (JProperty jProp in jProps) { if (jProp.Name == Constants.V4OdataNextLink) { isNextLinkPropExist = true; break; } } if (isNextLinkPropExist) { passed = true; } else { passed = false; detail.ErrorMessage = string.Format("The feed has {0} entities totally, but it only display {1} entities and there is no NextLink annotation.", totalCount, entries.Count); } } else { passed = null; detail.ErrorMessage = string.Format("The response of feed {0} has only one page, so can not test partial results.", entitySet); } } else { passed = null; detail.ErrorMessage = string.Format("The response of feed {0} does not have \"@Odata.count\" annotation so it cannot get the total count of entities.", entitySet); } } else { passed = null; detail.ErrorMessage = "Cannot get response from above URI."; } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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; ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name); var restrictions = AnnotationsHelper.GetExpandRestrictions(context.MetadataDocument, context.VocCapabilities); if (string.IsNullOrEmpty(restrictions.Item1) || null == restrictions.Item3 || !restrictions.Item3.Any()) { detail.ErrorMessage = "Cannot find any appropriate entity-sets which supports $expand system query options."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } // Set a expected level number as 2, and store it in the parameter expectedLevel. int expectedLevels = 2; string entitySetName = restrictions.Item1; string entityTypeShortName = entitySetName.MapEntitySetNameToEntityTypeShortName(); string[] navigPropNames = MetadataHelper.GetNavigPropNamesRecurseByLevels(entityTypeShortName, context.MetadataDocument, expectedLevels); string url = string.Format("{0}/{1}?$expand=*($levels={2})", context.ServiceBaseUri.OriginalString.TrimEnd('/'), entitySetName, expectedLevels); var resp = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); detail = new ExtensionRuleResultDetail(this.Name, url, "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 || !entities.Any()) { detail.ErrorMessage = string.Format("Cannot find any entities from the entity-set '{0}'", entitySetName); info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } bool isFirstLevelEmpty = false; int levelsCounter = 0; JObject entry = null; foreach (var en in entities) { levelsCounter = 0; entry = en as JObject; isFirstLevelEmpty = false; for (int i = 0; i < expectedLevels; i++) { if (entry != null && JTokenType.Object == entry.Type) { var navigPropVal = entry[navigPropNames[i]]; if (navigPropVal != null) { levelsCounter++; entry = navigPropVal.Type == JTokenType.Array ? navigPropVal.First as JObject : navigPropVal as JObject; if (entry == null) { isFirstLevelEmpty = true; break; } } } } if (expectedLevels == levelsCounter) { passed = true; } else if (!(levelsCounter < expectedLevels && isFirstLevelEmpty)) // If not no data { passed = false; detail.ErrorMessage = "The service does not execute an accurate result on the system query option '$levels' for expanded properties."; break; } } } else { passed = false; detail.ErrorMessage = "The service does not support the system query option '$levels' for expanded properties."; } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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; if (context.PayloadType == RuleEngine.PayloadType.Feed) { JObject feed; context.ResponsePayload.TryToJObject(out feed); var entries = JsonParserHelper.GetEntries(feed); foreach (JObject entry in entries) { if (entry != null && entry.Type == JTokenType.Object) { var jProps = entry.Children(); // New a string to record the annotation name. string record = string.Empty; foreach (JProperty jProp in jProps) { if (JsonSchemaHelper.IsJSONArrayOrPrimitiveAnnotation(jProp.Name)) { record = jProp.Name; } else { if (record == string.Empty) { continue; } else { // Prase the annotation name to two parts. string[] splitedStr = record.Split('@'); // If the string before the sign "@" are the same with property name, this rule will passed. if (jProp.Name == splitedStr[0]) { passed = true; record = string.Empty; continue; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); break; } } } } } } } else if (context.PayloadType == RuleEngine.PayloadType.Entry) { JObject entry; context.ResponsePayload.TryToJObject(out entry); if (entry != null && entry.Type == JTokenType.Object) { var jProps = entry.Children(); // New a string to record the annotation name. string record = string.Empty; foreach (JProperty jProp in jProps) { if (JsonSchemaHelper.IsJSONArrayOrPrimitiveAnnotation(jProp.Name)) { record = jProp.Name; } else { if (record == string.Empty) { continue; } else { // Prase the annotation name to two parts. string[] splitedStr = record.Split('@'); // If the string before the sign "@" are the same with property name, this rule will passed. if (jProp.Name == splitedStr[0]) { passed = true; record = string.Empty; continue; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); break; } } } } } } return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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; bool isDefinedInMetadata = false; bool isAnnotatingProNext = false; bool isAnnotatingProPrevious = false; JObject allobject; context.ResponsePayload.TryToJObject(out allobject); // Access the metadata document and get the node which will be used. string xpath = string.Format(@"//*[local-name()='EntityType']/*[local-name()='Property']", context.EntityTypeShortName); XElement metadata = XElement.Parse(context.MetadataDocument); var propNodesList = metadata.XPathSelectElements(xpath, ODataNamespaceManager.Instance); // If PayloadType is Feed, verify as below, else is Entry. if (context.PayloadType.Equals(RuleEngine.PayloadType.Feed)) { var entries = JsonParserHelper.GetEntries(allobject); foreach (JObject entry in entries) { var jProps = entry.Children(); foreach (JProperty jProp in jProps) { // Whether json property is annotation. if (JsonSchemaHelper.IsAnnotation(jProp.Name) && !jProp.Name.StartsWith("@")) { if (jProp.Name.Contains("@")) { // Parse the annotation name to two parts. string annotatedPro = jProp.Name.Remove(jProp.Name.LastIndexOf("@"), (jProp.Name.Length - jProp.Name.LastIndexOf("@"))); JProperty nextJProperty = ((JProperty)jProp.Next); JProperty previousJProperty = ((JProperty)jProp.Previous); // Compare the navigation properties of navigation links, foreach (var propNode in propNodesList) { if (propNode.Attribute("Name").ToString().Contains(annotatedPro)) { isDefinedInMetadata = true; break; } else { isDefinedInMetadata = false; } } // Whether the property defined in metadata. if (isDefinedInMetadata && nextJProperty != null) { if (nextJProperty.Name.ToString().Equals(annotatedPro)) { if ((nextJProperty.Value.Type == JTokenType.Array) || (nextJProperty.Value.Type != JTokenType.Object)) { isAnnotatingProNext = true; } else if ((nextJProperty.Value.Type == JTokenType.Object)) { if ((context.Version == ODataVersion.V3) && (jProp.Value.ToString().StripOffDoubleQuotes().StartsWith("Edm.Geography") || jProp.Value.ToString().StripOffDoubleQuotes().StartsWith("Edm.Geometry"))) { isAnnotatingProNext = true; } else if ((context.Version == ODataVersion.V4) && (jProp.Value.ToString().StripOffDoubleQuotes().TrimStart('#').StartsWith("Geography") || jProp.Value.ToString().StripOffDoubleQuotes().TrimStart('#').StartsWith("Geometry"))) { isAnnotatingProNext = true; } else { isAnnotatingProNext = false; } } } else if (previousJProperty.Name.ToString().Equals(annotatedPro)) { if ((previousJProperty.Value.Type == JTokenType.Array) || (nextJProperty.Value.Type != JTokenType.Object)) { isAnnotatingProPrevious = true; } else if ((previousJProperty.Value.Type == JTokenType.Object)) { if ((context.Version == ODataVersion.V3) && (jProp.Value.ToString().StripOffDoubleQuotes().StartsWith("Edm.Geography") || jProp.Value.ToString().StripOffDoubleQuotes().StartsWith("Edm.Geometry"))) { isAnnotatingProNext = true; } else if ((context.Version == ODataVersion.V4) && (jProp.Value.ToString().StripOffDoubleQuotes().TrimStart('#').StartsWith("Geography") || jProp.Value.ToString().StripOffDoubleQuotes().TrimStart('#').StartsWith("Geometry"))) { isAnnotatingProNext = true; } else { isAnnotatingProNext = false; } } } // If isAnnotatingProNext or isAnnotatingProPrevious is true, it means the name and value of annotation is not null. if (isAnnotatingProNext || isAnnotatingProPrevious) { passed = true; } else { passed = false; } } } } } } } else { if (allobject != null) { var jProps = allobject.Children(); // New a string to record the annotation name. string recordName = string.Empty; string recordValue = string.Empty; foreach (JProperty jProp in jProps) { // Whether json property is annotation. if (JsonSchemaHelper.IsAnnotation(jProp.Name) && !jProp.Name.StartsWith("@")) { if (jProp.Name.Contains("@")) { // Prase the annotation name to two parts. string annotatedPro = jProp.Name.Remove(jProp.Name.LastIndexOf("@"), (jProp.Name.Length - jProp.Name.LastIndexOf("@"))); JProperty nextJProperty = ((JProperty)jProp.Next); JProperty previousJProperty = ((JProperty)jProp.Previous); // Compare the navigation properties of navigation links, foreach (var propNode in propNodesList) { if (propNode.Attribute("Name").ToString().Contains(annotatedPro)) { isDefinedInMetadata = true; break; } else { isDefinedInMetadata = false; } } // Whether the property defined in metadata. if (isDefinedInMetadata && nextJProperty != null) { if (nextJProperty.Name.ToString().Equals(annotatedPro)) { if ((nextJProperty.Value.Type == JTokenType.Array) || (nextJProperty.Value.Type != JTokenType.Object)) { isAnnotatingProNext = true; } else if ((nextJProperty.Value.Type == JTokenType.Object)) { if ((context.Version == ODataVersion.V3) && (jProp.Value.ToString().StripOffDoubleQuotes().StartsWith("Edm.Geography") || jProp.Value.ToString().StripOffDoubleQuotes().StartsWith("Edm.Geometry"))) { isAnnotatingProNext = true; } else if ((context.Version == ODataVersion.V4) && (jProp.Value.ToString().StripOffDoubleQuotes().TrimStart('#').StartsWith("Geography") || jProp.Value.ToString().StripOffDoubleQuotes().TrimStart('#').StartsWith("Geometry"))) { isAnnotatingProNext = true; } else { isAnnotatingProNext = false; } } } else if (previousJProperty.Name.ToString().Equals(annotatedPro)) { if ((previousJProperty.Value.Type == JTokenType.Array) || (nextJProperty.Value.Type != JTokenType.Object)) { isAnnotatingProPrevious = true; } else if ((previousJProperty.Value.Type == JTokenType.Object)) { if ((context.Version == ODataVersion.V3) && (jProp.Value.ToString().StripOffDoubleQuotes().StartsWith("Edm.Geography") || jProp.Value.ToString().StripOffDoubleQuotes().StartsWith("Edm.Geometry"))) { isAnnotatingProNext = true; } else if ((context.Version == ODataVersion.V4) && (jProp.Value.ToString().StripOffDoubleQuotes().TrimStart('#').StartsWith("Geography") || jProp.Value.ToString().StripOffDoubleQuotes().TrimStart('#').StartsWith("Geometry"))) { isAnnotatingProNext = true; } else { isAnnotatingProNext = false; } } } // If isAnnotatingProNext or isAnnotatingProPrevious is true, it means the name and value of annotation is not null. if (isAnnotatingProNext || isAnnotatingProPrevious) { passed = true; } else { passed = false; } } } } } } } if (passed == false) { info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); } return(passed); }
/// <summary> /// Verifies the service implementation feature. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if the service implementation feature 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 svcStatus = ServiceStatus.GetInstance(); string url = svcStatus.RootURL.TrimEnd('/'); var detail = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, string.Empty); JObject serviceJO; svcStatus.ServiceDocument.TryToJObject(out serviceJO); JArray serviceOA = JsonParserHelper.GetEntries(serviceJO); string xpath = string.Format(@"//*[local-name()='FunctionImport']"); XElement md = XElement.Parse(svcStatus.MetadataDocument); XElement functionImport = md.XPathSelectElement(xpath, ODataNamespaceManager.Instance); if (functionImport == null) { detail.ErrorMessage = "The service has no function Import."; info = new ExtensionRuleViolationInfo(new Uri(url), string.Empty, detail); return(passed); } string functionShortName = functionImport.Attribute("Function").Value.GetLastSegment(); XElement function = md.XPathSelectElement(string.Format(@"//*[local-name()='Function' and @Name='{0}' and not (@IsBound='true')]", functionShortName), ODataNamespaceManager.Instance); string parameterString = string.Empty; List <KeyValuePair <string, string> > paralist = new List <KeyValuePair <string, string> >(); if (function != null) { IEnumerable <XElement> parameters = function.XPathSelectElements(@"./*[local-name()='Parameter' and @Nullable='false']"); foreach (XElement pa in parameters) { string value = string.Empty; if (EdmTypeManager.IsEdmSimpleType(pa.Attribute("Type").Value)) { IEdmType typeInterface = EdmTypeManager.GetEdmType(pa.Attribute("Type").Value); if (typeInterface != null) { value = typeInterface.GetXmlValueTemplate(); } } if (!string.IsNullOrEmpty(value)) { KeyValuePair <string, string> kv = new KeyValuePair <string, string>(pa.Attribute("Name").Value, value); paralist.Add(kv); } else { detail.ErrorMessage = "Parameter type is not supported by this test."; info = new ExtensionRuleViolationInfo(new Uri(url), string.Empty, detail); return(passed); } } } for (int i = 0; i < paralist.Count; i++) { if (i == 0) { parameterString = "(" + paralist[i].Key + "=" + paralist[i].Value; } else if (i < paralist.Count - 1) { parameterString += "," + paralist[i].Key + "=" + paralist[i].Value; } else if (i == paralist.Count - 1) { parameterString += "," + paralist[i].Key + "=" + paralist[i].Value + ")"; } } url += @"/" + functionShortName + parameterString; Response response = WebHelper.GetEntity(url); if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.NoContent) { detail = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, string.Empty); passed = true; } else { passed = false; } info = new ExtensionRuleViolationInfo(new Uri(url), string.Empty, detail); return(passed); }
/// <summary> /// Verifies the service implementation feature. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if the service implementation feature passes; false otherwise</returns> public override bool?Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool?passed = null; ExtensionRuleResultDetail detail = null; List <string> entitySetURLs = MetadataHelper.GetEntitySetURLs(); foreach (string entitySetUrl in entitySetURLs) { string entityTypeShortName = entitySetUrl.MapEntitySetNameToEntityTypeShortName(); Tuple <string, string> key = MetadataHelper.GetKeyProperty(entityTypeShortName); Response resp = WebHelper.Get(new Uri(context.ServiceBaseUri + "/" + entitySetUrl), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); if (null == resp || HttpStatusCode.OK != resp.StatusCode) { continue; } JObject feed; resp.ResponsePayload.TryToJObject(out feed); if (feed == null || JTokenType.Object != feed.Type) { continue; } JArray entities = JsonParserHelper.GetEntries(feed); string identity = entities[0][key.Item1].ToString(); string url = context.ServiceBaseUri + "/" + entitySetUrl + "(" + (key.Item2.Equals("Edm.String") ? "\'" + identity + "\'" : identity) + ")"; resp = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); detail = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, ""); if (null == resp || HttpStatusCode.OK != resp.StatusCode) { passed = false; break; } resp.ResponsePayload.TryToJObject(out feed); if (feed == null || JTokenType.Object != feed.Type) { passed = false; break; } JArray entity = JsonParserHelper.GetEntries(feed); if (feed[key.Item1] != null && feed[key.Item1].ToString().Equals(identity)) { passed = true; break; } passed = false; break; } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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; JObject entry; context.ResponsePayload.TryToJObject(out entry); if (entry != null && entry.Type == JTokenType.Object && context.OdataMetadataType == ODataMetadataType.MinOnly) { JsonParserHelper.ClearProperyValsList(); List <JToken> odataMetadataVals = JsonParserHelper.GetSpecifiedPropertyValsFromEntryPayload(entry, Constants.OdataV4JsonIdentity, MatchType.Equal); JsonParserHelper.ClearProperyValsList(); List <JToken> associationLinkVals = JsonParserHelper.GetSpecifiedPropertyValsFromEntryPayload(entry, Constants.OdataAssociationLinkPropertyNameSuffix, MatchType.Contained); string url = string.Empty; if (odataMetadataVals.Count == 1) { string odataMetadataValStr = odataMetadataVals[0].ToString().Trim('"'); int index = odataMetadataValStr.IndexOf(Constants.Metadata); url = odataMetadataValStr.Remove(index, odataMetadataValStr.Length - index); foreach (var associationLinkVal in associationLinkVals) { if (Uri.IsWellFormedUriString(associationLinkVal.ToString().Trim('"'), UriKind.Relative)) { url += associationLinkVal.ToString().Trim('"') + @"/$ref"; } else { url = associationLinkVal.ToString().Trim('"'); } Uri uri = new Uri(url, UriKind.RelativeOrAbsolute); // Send a request with "application/json;odata=minimalmetadata" in Accept header. string acceptHeader = Constants.V4AcceptHeaderJsonMinimalMetadata; Response response = WebHelper.Get(uri, acceptHeader, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); // If response's status code is not equal to 200, it will indicate the url cannot be computed. if (response.StatusCode != HttpStatusCode.OK) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); break; } } } } return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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 serviceStatus = ServiceStatus.GetInstance(); var detail = new ExtensionRuleResultDetail(this.Name); string[] entitySetUrls = ContextHelper.GetFeeds(serviceStatus.ServiceDocument, this.PayloadFormat.Value).ToArray(); string entitySetName = entitySetUrls.First().MapEntitySetURLToEntitySetName(); string entityTypeShortName = entitySetName.MapEntitySetNameToEntityTypeShortName(); string url = string.Format("{0}/{1}", serviceStatus.RootURL.TrimEnd('/'), entitySetName); Response response = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, null); detail = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, string.Empty, response); detail.URI = url; detail.ResponsePayload = response.ResponsePayload; detail.ResponseHeaders = response.ResponseHeaders; detail.ResponseStatusCode = response.StatusCode.ToString(); detail.HTTPMethod = "GET"; if (response.StatusCode != HttpStatusCode.OK) { detail.ErrorMessage = "HTTP Error was returned: " + response.StatusCode.ToString() + " with Reponse Body: " + response.ResponsePayload; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail); return(passed); } JObject feed; response.ResponsePayload.TryToJObject(out feed); var entries = JsonParserHelper.GetEntries(feed); var entry = entries.First(); var entryUrl = string.Empty; if (null != entry[Constants.V4OdataId]) { entryUrl = entry[Constants.V4OdataId].ToString().TrimEnd('\\'); } else { detail.ErrorMessage = "Cannot get the entity-id from the current entity."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail); return(passed); } try { Uri testuri = new Uri(entryUrl); } catch { detail.ErrorMessage = "The entity URL provided by @odata.id is not a valid URL. This is what was returned: " + entryUrl; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail); passed = false; return(passed); } // Use the XPath query language to access the metadata document and get all NavigationProperty. XElement metadata = XElement.Parse(serviceStatus.MetadataDocument); string xpath = string.Format(@"//*[local-name()='EntityType' and @Name='{0}']/*[local-name()='Property']", entityTypeShortName); IEnumerable <XElement> props = metadata.XPathSelectElements(xpath, ODataNamespaceManager.Instance); List <string> propNames = new List <string>(); foreach (var prop in props) { propNames.Add(prop.Attribute("Name").Value); } url = string.Format("{0}/{1}/$value", entryUrl.TrimEnd('/'), propNames[0]); response = WebHelper.Get(url, null, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); detail = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, string.Empty, response); detail.URI = url; detail.ResponsePayload = response.ResponsePayload; detail.ResponseHeaders = response.ResponseHeaders; detail.HTTPMethod = "GET"; detail.ResponseStatusCode = response.StatusCode.ToString(); // Get the value of propNames[0] property in entry payload and verify whether this value is equal to /$value payload value. if (response.StatusCode == HttpStatusCode.OK && entry[propNames[0]].ToString().Equals(response.ResponsePayload)) { passed = true; } else { passed = false; detail.ErrorMessage = "The service does not support '/$value' segment."; } info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail); return(passed); }
/// <summary> /// Verify Entry.Core.4063 /// </summary> /// <param name="context">Service context</param> /// <param name="info">out parameter 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; JObject entry; context.ResponsePayload.TryToJObject(out entry); if (entry != null && entry.Type == JTokenType.Object) { if (ODataVersion.V3 == context.Version) { JsonParserHelper.ClearPropertyNamesList(); List <string> odataMediaAnnotations = JsonParserHelper.GetSpecifiedPropertyNamesFromEntryPayload(entry, Constants.OdataMedia, MatchType.Contained); if (0 < odataMediaAnnotations.Count) { var temp = from o in odataMediaAnnotations where o.Contains(Constants.OdataMediaEtag) select o; if (0 < temp.Count()) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); } } } else if (ODataVersion.V4 == context.Version) { JsonParserHelper.ClearPropertyNamesList(); List <string> odataMediaAnnotations = JsonParserHelper.GetSpecifiedPropertyNamesFromEntryPayload(entry, Constants.V4OdataMedia, MatchType.Contained); if (0 < odataMediaAnnotations.Count) { var temp = from o in odataMediaAnnotations where o.Contains(Constants.V4OdataMediaEtag) select o; if (0 < temp.Count()) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); } } } } return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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; JObject allobject; context.ResponsePayload.TryToJObject(out allobject); // If PayloadType is Feed, verify as below, eles is Entry. if (context.PayloadType.Equals(RuleEngine.PayloadType.Feed)) { var entries = JsonParserHelper.GetEntries(allobject); foreach (JObject entry in entries) { var o = (JObject)entry; var jProps = o.Children(); foreach (JProperty jProp in jProps) { if (JsonSchemaHelper.IsAnnotation(jProp.Name)) { if (Regex.IsMatch(jProp.Name, @"[a-zA-Z0-9]+\.[a-zA-Z0-9]+")) { passed = true; continue; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); return passed; } } } } } else { var o = (JObject)allobject; var jProps = o.Children(); foreach (JProperty jProp in jProps) { if (JsonSchemaHelper.IsAnnotation(jProp.Name)) { if (Regex.IsMatch(jProp.Name, @"[a-zA-Z0-9]+\.[a-zA-Z0-9]+")) { passed = true; continue; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); return passed; } } } } return passed; }
/// <summary> /// Verifies the service implementation feature. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if the service implementation feature passes; false otherwise</returns> public override bool?Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool?passed = null; Response resp = WebHelper.Get(new Uri(context.ServiceBaseUri + "/$all"), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name, context.ServiceBaseUri + "/$all", HttpMethod.Get, context.RequestHeaders.ToString()); info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); if (null == resp || HttpStatusCode.OK != resp.StatusCode) { return(passed = false); } JObject allFeed; resp.ResponsePayload.TryToJObject(out allFeed); if (allFeed == null || JTokenType.Object != allFeed.Type) { return(passed = false); } JArray allEntities = JsonParserHelper.GetEntries(allFeed); passed = true; List <string> entitySetURLs = MetadataHelper.GetEntitySetURLs(); foreach (string entitySetUrl in entitySetURLs) { string entityTypeShortName = entitySetUrl.MapEntitySetNameToEntityTypeShortName(); Tuple <string, string> key = MetadataHelper.GetKeyProperty(entityTypeShortName); resp = WebHelper.Get(new Uri(context.ServiceBaseUri + "/" + entitySetUrl), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); if (null == resp || HttpStatusCode.OK != resp.StatusCode) { continue; } JObject feed; resp.ResponsePayload.TryToJObject(out feed); if (feed == null || JTokenType.Object != feed.Type) { continue; } JArray entities = JsonParserHelper.GetEntries(feed); foreach (JToken entity in entities) { if (!Find(allEntities, key.Item1, entity[key].ToString())) { return(passed = false); } } } return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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; JObject entry; context.ResponsePayload.TryToJObject(out entry); List <string> expandProps = ODataUriAnalyzer.GetQueryOptionValsFromUrl(context.Destination.ToString(), @"expand"); if (entry != null && entry.Type == JTokenType.Object && expandProps.Count > 0) { var props = entry.Children(); foreach (JProperty prop in props) { if (expandProps.Contains(prop.Name)) { passed = null; if (prop.Value.Type == JTokenType.Object) { JObject jObj = prop.Value as JObject; JsonParserHelper.ClearPropertiesList(); if (JsonParserHelper.GetSpecifiedPropertiesFromEntryPayload(jObj, Constants.OdataV4JsonIdentity).Count > 0) { passed = true; break; } else { passed = false; } } else if (prop.Value.Type == JTokenType.Array) { JArray jArr = prop.Value as JArray; if (JsonParserHelper.GetSpecifiedPropertiesFromFeedPayload(jArr, Constants.OdataV4JsonIdentity).Count > 0) { passed = true; break; } else { passed = false; } } } } if (passed == false) { info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); } } return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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 = true; ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name); var payloadFormat = context.ServiceDocument.GetFormatFromPayload(); string[] feeds = ContextHelper.GetFeeds(context.ServiceDocument, payloadFormat).ToArray(); string entitySetName = feeds.First().MapEntitySetURLToEntitySetName(); Uri firstFeedFullUrl = new Uri(string.Format("{0}/{1}", context.DestinationBasePath.TrimEnd('/'), entitySetName)); Response response = WebHelper.Get(firstFeedFullUrl, Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); detail = new ExtensionRuleResultDetail(this.Name, firstFeedFullUrl.AbsoluteUri, "GET", StringHelper.MergeHeaders(Constants.V4AcceptHeaderJsonFullMetadata, context.RequestHeaders), response); if (response != null && response.StatusCode != null) { JObject feed; response.ResponsePayload.TryToJObject(out feed); var entries = JsonParserHelper.GetEntries(feed); foreach (JObject entry in entries) { var jProps = entry.Children(); foreach (JProperty jProp in jProps) { if (JsonSchemaHelper.IsAnnotation(jProp.Name) && jProp.Name.EndsWith("@" + Constants.OdataType) && !jProp.Name.StartsWith("@" + Constants.OdataType)) { string typeValue = jProp.Value.ToString().TrimStart('#'); if (typeValue.Contains("Collection(")) { typeValue = typeValue.Substring(typeValue.IndexOf("(") + 1, typeValue.LastIndexOf(")") - typeValue.IndexOf("(") - 1); } // Don't contains dot means it is primitive value or collection. if (!typeValue.Contains(".")) { if (PrimitiveDataTypes.NonQualifiedTypes.Contains(typeValue)) { passed = true; } else { passed = false; detail.ErrorMessage += string.Format("The type {0} is not defined in OData-CSDL.", typeValue); break; } } } } if (passed == false) // Break to foreach all if anyone of them cannot match the rule { break; } } } else { passed = false; detail.ErrorMessage = string.Format(Constants.ErrorURI, "GET", firstFeedFullUrl.AbsoluteUri, "failed"); } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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; ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name); var restrictions = new Dictionary <string, Tuple <List <NormalProperty>, List <NavigProperty> > >(); if (!AnnotationsHelper.GetExpandRestrictions(context.MetadataDocument, context.VocCapabilities, ref restrictions)) { detail.ErrorMessage = "Cannot find any appropriate entity-sets which supports $expand system query options."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } if (!AnnotationsHelper.IsSuitableNavigationProperty(NavigationRoughType.CollectionValued, ref restrictions)) { detail.ErrorMessage = "Cannot find any collection-valued navigation properties in any entity-sets which supports $expand system query options."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } string entitySet = string.Empty; string navigProp = string.Empty; 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; } entitySet = r.Key; foreach (var np in r.Value.Item2) { navigProp = np.NavigationPropertyName; string nEntityTypeShortName = np.NavigationPropertyType.RemoveCollectionFlag().GetLastSegment(); var rest = AnnotationsHelper.GetCountRestrictions(context.MetadataDocument, context.VocCapabilities); if (string.IsNullOrEmpty(rest.Item1) || null == rest.Item2 || !rest.Item2.Any() || null == rest.Item3 || !rest.Item3.Any()) { continue; } break; } break; } if (string.IsNullOrEmpty(entitySet)) { detail.ErrorMessage = "Cannot find an appropriate entity-set which supports $expand system query option."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } if (string.IsNullOrEmpty(navigProp)) { detail.ErrorMessage = "Cannot get expanded entities because cannot get collection type of navigation property from metadata"; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } string url = string.Format("{0}/{1}?$expand={2}($count=true)", context.ServiceBaseUri.OriginalString.TrimEnd('/'), entitySet, navigProp); Uri uri = new Uri(url); Response resp = WebHelper.Get(uri, Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); detail = new ExtensionRuleResultDetail(this.Name, uri.AbsoluteUri, "GET", StringHelper.MergeHeaders(Constants.AcceptHeaderJson, context.RequestHeaders), resp); detail.URI = url; detail.ResponsePayload = resp.ResponsePayload; detail.ResponseHeaders = resp.ResponseHeaders; detail.HTTPMethod = "GET"; detail.ResponseStatusCode = resp.StatusCode.ToString(); if (resp != null && resp.StatusCode == HttpStatusCode.OK) { JObject feed; resp.ResponsePayload.TryToJObject(out feed); if (null == feed) { detail.ErrorMessage = "Cannot find any entity-sets in the service.\r\n"; info = new ExtensionRuleViolationInfo(uri, resp.ResponsePayload, detail); return(passed); } JObject entry = null; var entities = JsonParserHelper.GetEntries(feed); foreach (var e in entities) { if (null != e[navigProp] && JTokenType.Array == e[navigProp].Type) { entry = e as JObject; break; } } if (null == entry) { detail.ErrorMessage = "Cannot find an appropriate entity which contains at least one collection-valued navigation property.\r\n"; info = new ExtensionRuleViolationInfo(uri, resp.ResponsePayload, detail); return(passed); } if (null != entry && JTokenType.Object == entry.Type) { JArray jArr = entry[navigProp] as JArray; int actualAmount = 0; JsonParserHelper.GetEntitiesNumFromCollectionValuedNavigProp(entry[Constants.V4OdataId].ToString(), entry, navigProp, context.RequestHeaders, ref actualAmount); if (null != entry[navigProp + Constants.V4OdataCount] && actualAmount == (int)entry[navigProp + Constants.V4OdataCount]) { passed = true; } else { passed = false; detail.ErrorMessage = "The service does not execute an accurate result on the system query option '$count' for expanded properties."; } } } else { passed = false; detail.ErrorMessage = "The service does not support the system query option '$count' for expanded properties."; } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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 serviceStatus = ServiceStatus.GetInstance(); var detail = new ExtensionRuleResultDetail(this.Name); List <EntityTypeElement> entityTypes = MetadataHelper.GetEntityTypeInheritance(serviceStatus.MetadataDocument, serviceStatus.ServiceDocument); if (!entityTypes.Any()) { detail.ErrorMessage = "Cannot find a derived entity type from metadata."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail); return(passed); } string entityTypeShortName = string.Empty; string entitySetUrl = string.Empty; string derivedTypeFullName = string.Empty; foreach (var entityType in entityTypes) { entityTypeShortName = entityType.EntityTypeShortName; derivedTypeFullName = string.Format("{0}.{1}", entityType.EntityTypeNamespace, entityTypeShortName); if (!string.IsNullOrEmpty(entityType.EntitySetName)) { entitySetUrl = entityType.EntitySetName.MapEntitySetNameToEntitySetURL(); } else { continue; } if (string.IsNullOrEmpty(entityTypeShortName) || string.IsNullOrEmpty(entitySetUrl) || string.IsNullOrEmpty(derivedTypeFullName)) { continue; } } if (string.IsNullOrEmpty(entitySetUrl)) { detail.ErrorMessage = string.Format("Cannot find the entity-set URL which is matched with {0}", entityTypeShortName); info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail); return(passed); } string url = string.Format("{0}/{1}/{2}", serviceStatus.RootURL, entitySetUrl, derivedTypeFullName); var resp = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, serviceStatus.DefaultHeaders); detail = new ExtensionRuleResultDetail(this.Name, url, "GET", StringHelper.MergeHeaders(Constants.V4AcceptHeaderJsonFullMetadata, serviceStatus.DefaultHeaders), resp); if (resp != null && resp.StatusCode == HttpStatusCode.OK) { JObject feed; resp.ResponsePayload.TryToJObject(out feed); if (feed != null && JTokenType.Object == feed.Type) { var entities = JsonParserHelper.GetEntries(feed).ToList(); var appropriateEntities = entities.FindAll(e => e[Constants.V4OdataType].ToString().Contains(derivedTypeFullName)).Select(e => e); if (entities.Count == appropriateEntities.Count()) { passed = true; } else { passed = false; detail.ErrorMessage = "The service does not execute an acculate result on casting to a derived type."; } } } else { passed = false; detail.ErrorMessage = JsonParserHelper.GetErrorMessage(resp.ResponsePayload); } info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail); return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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; ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name); var filterRestrictions = AnnotationsHelper.GetFilterRestrictions(context.MetadataDocument, context.VocCapabilities); if (string.IsNullOrEmpty(filterRestrictions.Item1) || null == filterRestrictions.Item2 || !filterRestrictions.Item2.Any()) { detail.ErrorMessage = "Cannot find an appropriate entity-set which supports $filter system query options in the service."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } string entitySet = filterRestrictions.Item1; string primitivePropName = filterRestrictions.Item2.First().PropertyName; string primitivePropType = filterRestrictions.Item2.First().PropertyType; string url = string.Format("{0}/{1}", context.ServiceBaseUri.OriginalString.TrimEnd('/'), entitySet); var resp = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); if (null == resp || HttpStatusCode.OK != resp.StatusCode) { detail.ErrorMessage = JsonParserHelper.GetErrorMessage(resp.ResponsePayload); info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } JObject feed; resp.ResponsePayload.TryToJObject(out feed); if (feed != null && JTokenType.Object == feed.Type) { var entities = JsonParserHelper.GetEntries(feed); string propVal = "Edm.String" == primitivePropType?string.Format("'{0}'", entities[0][primitivePropName].ToString()) : entities[0][primitivePropName].ToString(); //var req = WebRequest.Create(string.Format("{0}?$filter={1} eq @test1&@test1={2}", url, primitivePropName, propVal)) as HttpWebRequest;; //resp = WebHelper.Get(req, RuleEngineSetting.Instance().DefaultMaximumPayloadSize); //REPLACE HEADER string requri = string.Format("{0}?$filter={1} eq @test1&@test1={2}", url, primitivePropName, propVal); resp = WebHelper.Get(requri, null, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); detail = new ExtensionRuleResultDetail(this.Name, requri, "GET", string.Empty, resp); if (resp.StatusCode == HttpStatusCode.OK) { JObject feed1; resp.ResponsePayload.TryToJObject(out feed1); if (feed1 != null && JTokenType.Object == feed1.Type) { var entities1 = JsonParserHelper.GetEntries(feed1).ToList(); var temp = entities1.FindAll(en => propVal == en[primitivePropName].ToString()).Select(en => en); if (entities1.Count() == temp.Count()) { passed = true; } else { passed = false; detail.ErrorMessage = "The service does not execute an accurate result on aliases in $filter expressions."; } } } else { passed = false; detail.ErrorMessage = JsonParserHelper.GetErrorMessage(resp.ResponsePayload); } } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); }
/// <summary> /// Verifies the service implementation feature. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if the service implementation feature passes; false otherwise</returns> public override bool?Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool?passed = null; List <ExtensionRuleResultDetail> details = new List <ExtensionRuleResultDetail>(); XmlDocument metadata = new XmlDocument(); metadata.LoadXml(ServiceStatus.GetInstance().MetadataDocument); string xPath = "//*[local-name()='EnumType']"; XmlNodeList enumTypes = metadata.SelectNodes(xPath, ODataNamespaceManager.Instance); foreach (XmlNode enumType in enumTypes) { xPath = "//*[local-name()='EntityType']"; XmlNodeList entityTypes = metadata.SelectNodes(xPath, ODataNamespaceManager.Instance); List <string> typeNames = new List <string> { enumType.ParentNode.Attributes["Namespace"].Value + "." + enumType.Attributes["Name"].Value }; if (enumType.ParentNode.Attributes["Alias"] != null) { typeNames.Add(enumType.ParentNode.Attributes["Alias"].Value + "." + enumType.Attributes["Name"].Value); } List <string> properties = null; foreach (XmlNode entityType in entityTypes) { properties = MetadataHelper.GetPropertiesWithSpecifiedTypeFromEntityType(entityType.Attributes["Name"].Value, ServiceStatus.GetInstance().MetadataDocument, typeNames); if (properties == null || properties.Count < 1) { continue; } string entitySetUrl = entityType.Attributes["Name"].Value.MapEntityTypeShortNameToEntitySetName(); Response resp = WebHelper.Get(new Uri(context.ServiceBaseUri + "/" + entitySetUrl), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); if (null == resp || HttpStatusCode.OK != resp.StatusCode) { continue; } JObject feed; resp.ResponsePayload.TryToJObject(out feed); if (feed == null || JTokenType.Object != feed.Type) { continue; } JArray entities = JsonParserHelper.GetEntries(feed); string enumValue = entities[0][properties[0].Split(',')[0]].ToString(); string url = context.ServiceBaseUri + "/" + entitySetUrl + "?$filter=" + properties[0].Split(',')[0] + " has " + typeNames[0] + "\'" + enumValue + "\'"; resp = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); details.Add(new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, "")); if (null == resp || HttpStatusCode.OK != resp.StatusCode) { passed = false; break; } resp.ResponsePayload.TryToJObject(out feed); if (feed == null || JTokenType.Object != feed.Type) { passed = false; break; } entities = JsonParserHelper.GetEntries(feed); foreach (JToken entity in entities) { Dictionary <string, ushort> map = buildEnumMapping(enumType); ushort expect, actual; if (!mappingToUshort(map, enumValue, out expect) || !mappingToUshort(map, entity[properties[0].Split(',')[0]].ToString(), out actual)) { passed = false; break; } if (enumType.Attributes["IsFlags"] != null && enumType.Attributes["IsFlags"].Value.Equals("true", StringComparison.OrdinalIgnoreCase)) { if ((expect & actual) != expect) { passed = false; break; } } else { if (expect != actual) { passed = false; break; } } //if (!entity[properties[0].Split(',')[0]].ToString().Equals(enumValue)) //{ passed = false; break; } } if (passed.HasValue && !passed.Value) { break; } else { passed = true; break; } } if (passed != null) { break; } } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, details); return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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; string odataTypeAnnotation = Constants.V4OdataType; if (context.Version == ODataVersion.V3) { odataTypeAnnotation = Constants.OdataType; } if (context.PayloadType == RuleEngine.PayloadType.Entry) { JObject entry; context.ResponsePayload.TryToJObject(out entry); if (entry != null && entry.Type == JTokenType.Object) { var jProps = entry.Children(); foreach (JProperty jProp in jProps) { if (jProp.Name.Equals(odataTypeAnnotation)) { passed = null; if (Uri.IsWellFormedUriString(jProp.Value.ToString().StripOffDoubleQuotes().TrimStart('#'), UriKind.Relative)) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); break; } } } } } else if (context.PayloadType == RuleEngine.PayloadType.Feed) { JObject feed; context.ResponsePayload.TryToJObject(out feed); var entries = JsonParserHelper.GetEntries(feed); foreach (JObject entry in entries) { if (entry != null && entry.Type == JTokenType.Object) { var jProps = entry.Children(); foreach (JProperty jProp in jProps) { if (jProp.Name.Equals(odataTypeAnnotation)) { passed = null; if (Uri.IsWellFormedUriString(jProp.Value.ToString().StripOffDoubleQuotes().TrimStart('#'), UriKind.Relative)) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); break; } } } } } } return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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; ServiceStatus serviceStatus = ServiceStatus.GetInstance(); TermDocuments termDocs = TermDocuments.GetInstance(); DataFactory dFactory = DataFactory.Instance(); var detail1 = new ExtensionRuleResultDetail(this.Name); var detail2 = new ExtensionRuleResultDetail(this.Name); var detail3 = new ExtensionRuleResultDetail(this.Name); List <string> keyPropertyTypes = new List <string>() { "Edm.Int32", "Edm.Int16", "Edm.Int64", "Edm.Guid", "Edm.String" }; List <EntityTypeElement> entityTypeElements = MetadataHelper.GetEntityTypes(serviceStatus.MetadataDocument, 1, keyPropertyTypes, null, NavigationRoughType.SingleValued).ToList(); if (null == entityTypeElements || 0 == entityTypeElements.Count()) { detail1.ErrorMessage = "To verify this rule it expects an entity type with Int32/Int64/Int16/Guid/String key property, but there is no this entity type in metadata so can not verify this rule."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1); return(passed); } string entityTypeShortName = string.Empty; string entitySetName = string.Empty; string entitySetUrl = string.Empty; string navigPropName = string.Empty; foreach (var en in entityTypeElements) { var matchEntity = en.EntitySetName.GetRestrictions(serviceStatus.MetadataDocument, termDocs.VocCapabilitiesDoc, new List <Func <string, string, string, List <NormalProperty>, List <NavigProperty>, bool> >() { AnnotationsHelper.GetExpandRestrictions, AnnotationsHelper.GetInsertRestrictions , AnnotationsHelper.GetDeleteRestrictions, AnnotationsHelper.GetUpdateRestrictions }); if (!string.IsNullOrEmpty(matchEntity.Item1) && matchEntity.Item2 != null && matchEntity.Item2.Any() && matchEntity.Item3 != null && matchEntity.Item3.Any()) { entityTypeShortName = en.EntityTypeShortName; entitySetName = matchEntity.Item1; entitySetUrl = entitySetName.MapEntitySetNameToEntitySetURL(); foreach (NavigProperty np in matchEntity.Item3) { string nEntityTypeShortName = np.NavigationPropertyType.RemoveCollectionFlag().GetLastSegment(); if (np.NavigationRoughType == NavigationRoughType.SingleValued && !nEntityTypeShortName.IsMediaType()) { navigPropName = np.NavigationPropertyName; break; } } } if (!string.IsNullOrEmpty(entitySetName) && !string.IsNullOrEmpty(navigPropName)) { break; } } if (string.IsNullOrEmpty(entitySetName) || string.IsNullOrEmpty(navigPropName)) { detail1.ErrorMessage = "Cannot find the appropriate entity-set URL to verify this rule."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1); return(passed); } string navigPropEntitySet = navigPropName.MapNavigationPropertyNameToEntitySetURL(entityTypeShortName); string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl; var additionalInfos = new List <AdditionalInfo>(); var reqData = dFactory.ConstructInsertedEntityData(entitySetName, entityTypeShortName, new List <string>() { navigPropName }, out additionalInfos); string reqDataStr = reqData.ToString(); bool isMediaType = !string.IsNullOrEmpty(additionalInfos.Last().ODataMediaEtag); var resp = WebHelper.CreateEntity(url, context.RequestHeaders, reqData, isMediaType, ref additionalInfos); detail1 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.Created == resp.StatusCode) { string entityId = additionalInfos.Last().EntityId; url = serviceStatus.RootURL.TrimEnd('/') + @"/" + navigPropEntitySet; resp = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, serviceStatus.DefaultHeaders); detail2 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, StringHelper.MergeHeaders(Constants.V4AcceptHeaderJsonFullMetadata, serviceStatus.DefaultHeaders), resp); if (resp.StatusCode.HasValue && HttpStatusCode.OK == resp.StatusCode) { JObject feed; resp.ResponsePayload.TryToJObject(out feed); var entities = JsonParserHelper.GetEntries(feed); if (entities.Any()) { string v4OdataIdVal = string.Empty; if (entities.First[Constants.V4OdataId] != null) { v4OdataIdVal = entities.First[Constants.V4OdataId].ToString(); } url = string.Format("{0}/{1}/$ref", entityId, navigPropName); reqDataStr = @"{ """ + Constants.V4OdataId + @""" : """ + v4OdataIdVal + @""" }"; bool hasEtag = additionalInfos.Last().HasEtag; resp = WebHelper.UpdateEntity(url, context.RequestHeaders, reqDataStr, HttpMethod.Put, hasEtag); detail3 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Put, string.Empty, resp, string.Empty, reqDataStr); if (null != resp && HttpStatusCode.NoContent == resp.StatusCode) { passed = true; } else { passed = false; detail3.ErrorMessage = "PUT to $ref failed by above URI"; } } } else { passed = false; detail2.ErrorMessage = "Get entity failed from above URI."; } // Restore the service. var resps = WebHelper.DeleteEntities(context.RequestHeaders, additionalInfos); } else { passed = false; detail1.ErrorMessage = "Created the new entity failed for above URI."; } var details = new List <ExtensionRuleResultDetail>() { detail1, detail2, detail3 }.RemoveNullableDetails(); info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details); return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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; ServiceStatus serviceStatus = ServiceStatus.GetInstance(); TermDocuments termDocs = TermDocuments.GetInstance(); DataFactory dFactory = DataFactory.Instance(); ExtensionRuleResultDetail detail1 = new ExtensionRuleResultDetail(this.Name); ExtensionRuleResultDetail detail2 = new ExtensionRuleResultDetail(this.Name); ExtensionRuleResultDetail detail3 = new ExtensionRuleResultDetail(this.Name); List <string> keyPropertyTypes = new List <string>() { "Edm.Int32", "Edm.Int16", "Edm.Int64", "Edm.Guid", "Edm.String" }; List <EntityTypeElement> entityTypeElements = MetadataHelper.GetEntityTypes(serviceStatus.MetadataDocument, 1, keyPropertyTypes, null, NavigationRoughType.CollectionValued).ToList(); if (entityTypeElements == null || entityTypeElements.Count == 0) { detail1.ErrorMessage = "To verify this rule it expects an entity type with Int32/Int64/Int16/Guid/String key property, but there is no this entity type in metadata so can not verify this rule."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1); return(passed); } foreach (var et in entityTypeElements) { string navigPropName = null; string navigPropRelatedEntitySetUrl = null; string navigPropRelatedEntityTypeKeyName = null; var matchEntity = et.EntitySetName.GetRestrictions(serviceStatus.MetadataDocument, termDocs.VocCapabilitiesDoc, new List <Func <string, string, string, List <NormalProperty>, List <NavigProperty>, bool> >() { AnnotationsHelper.GetDeleteRestrictions, AnnotationsHelper.GetInsertRestrictions }); if (string.IsNullOrEmpty(matchEntity.Item1) || matchEntity.Item2 == null || !matchEntity.Item2.Any() || matchEntity.Item3 == null || !matchEntity.Item3.Any()) { continue; } foreach (var np in matchEntity.Item3) { navigPropName = np.NavigationPropertyName; string navigEntityTypeShortName = np.NavigationPropertyType.RemoveCollectionFlag().GetLastSegment(); List <NormalProperty> navigKeyProps = MetadataHelper.GetKeyProperties(serviceStatus.MetadataDocument, navigEntityTypeShortName).ToList(); if (navigKeyProps.Count == 1 && keyPropertyTypes.Contains(navigKeyProps[0].PropertyType)) { navigPropRelatedEntitySetUrl = navigEntityTypeShortName.MapEntityTypeShortNameToEntitySetURL(); navigPropRelatedEntityTypeKeyName = navigKeyProps[0].PropertyName; break; } } if (!string.IsNullOrEmpty(navigPropRelatedEntityTypeKeyName) && !string.IsNullOrEmpty(navigPropRelatedEntitySetUrl)) { string entitySetUrl = et.EntitySetName.MapEntitySetNameToEntitySetURL(); string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl; var additionalInfos = new List <AdditionalInfo>(); var reqData = dFactory.ConstructInsertedEntityData(et.EntitySetName, et.EntityTypeShortName, null, out additionalInfos); string reqDataStr = reqData.ToString(); bool isMediaType = !string.IsNullOrEmpty(additionalInfos.Last().ODataMediaEtag); var resp = WebHelper.CreateEntity(url, context.RequestHeaders, reqData, isMediaType, ref additionalInfos); detail1 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); if (resp.StatusCode.HasValue && HttpStatusCode.Created == resp.StatusCode) { string entityId = additionalInfos.Last().EntityId; url = serviceStatus.RootURL.TrimEnd('/') + @"/" + navigPropRelatedEntitySetUrl; resp = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, serviceStatus.DefaultHeaders); detail2 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, StringHelper.MergeHeaders(Constants.V4AcceptHeaderJsonFullMetadata, serviceStatus.DefaultHeaders), resp, string.Empty, reqDataStr); detail2.URI = url; detail2.ResponsePayload = resp.ResponsePayload; detail2.ResponseHeaders = resp.ResponseHeaders; detail2.HTTPMethod = "GET"; detail2.ResponseStatusCode = resp.StatusCode.ToString(); if (null != resp && resp.StatusCode == HttpStatusCode.OK) { JObject feed; resp.ResponsePayload.TryToJObject(out feed); var entities = JsonParserHelper.GetEntries(feed); if (entities.Count > 0) { // Use the HTTP method POST to link the navigation property for an entity. reqDataStr = @"{""" + Constants.V4OdataId + @""" : """ + entities[0][Constants.V4OdataId].ToString() + @"""}"; url = string.Format("{0}/{1}/$ref", entityId.TrimEnd('/'), navigPropName.TrimEnd('/')); resp = WebHelper.CreateEntity(url, reqDataStr); detail3 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); if (null != resp && resp.StatusCode == HttpStatusCode.NoContent) { passed = true; } else { passed = false; detail3.ErrorMessage = "Created the new entity failed for above URI."; } } } else { passed = false; detail2.ErrorMessage = "Get entity failed from above URI."; } // Restore the service. var resps = WebHelper.DeleteEntities(context.RequestHeaders, additionalInfos); } else { passed = false; detail1.ErrorMessage = "Created the new entity failed for above URI."; } } if (false == passed) { break; } } var details = new List <ExtensionRuleResultDetail>() { detail1, detail2, detail3 }.RemoveNullableDetails(); info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details); return(passed); }
/// <summary> /// Verifies the service implementation feature. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if the service implementation feature 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; ServiceStatus serviceStatus = ServiceStatus.GetInstance(); TermDocuments termDocs = TermDocuments.GetInstance(); DataFactory dFactory = DataFactory.Instance(); var detail = new ExtensionRuleResultDetail(this.Name, serviceStatus.RootURL, HttpMethod.Post, string.Empty); List <string> keyPropertyTypes = new List <string>() { "Edm.Int32", "Edm.Int16", "Edm.Int64", "Edm.Guid", "Edm.String" }; var entityTypeElements = MetadataHelper.GetEntityTypes(serviceStatus.MetadataDocument, 1, keyPropertyTypes, null, NavigationRoughType.None); if (null == entityTypeElements || 0 == entityTypeElements.Count()) { detail.ErrorMessage = "To verify this rule it expects an entity type with Int32/Int64/Int16/Guid/String key property, but there is no this entity type in metadata so can not verify this rule."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail); return(passed); } string entitySet = string.Empty; string navigProp = string.Empty; NavigationRoughType navigRoughType = NavigationRoughType.None; EntityTypeElement entityType = new EntityTypeElement(); foreach (var en in entityTypeElements) { if (!string.IsNullOrEmpty(en.EntitySetName) && en.NavigationProperties.Count > 0) { foreach (NavigProperty np in en.NavigationProperties) { string npTypeFullName = np.NavigationPropertyType.RemoveCollectionFlag(); XmlDocument metadata = new XmlDocument(); metadata.LoadXml(context.MetadataDocument); if (context.ContainsExternalSchema) { metadata.LoadXml(context.MergedMetadataDocument); } XmlNode npXmlNode; MetadataHelper.GetTypeNode(npTypeFullName, metadata, out npXmlNode); if (!(npXmlNode.Attributes["HasStream"] != null ? npXmlNode.Attributes["HasStream"].Value.Equals("true") : false)) { navigProp = np.NavigationPropertyName; navigRoughType = np.NavigationRoughType; entityType = en; entitySet = en.EntitySetName; break; } } if (!string.IsNullOrEmpty(entitySet)) { break; } } } if (string.IsNullOrEmpty(entitySet) || string.IsNullOrEmpty(navigProp)) { detail.ErrorMessage = "Cannot find an entity-set URL which can be execute the deep insert operation on it."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail); return(passed); } string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySet; var additionalInfos = new List <AdditionalInfo>(); var reqData = dFactory.ConstructInsertedEntityData(entityType.EntitySetName, entityType.EntityTypeShortName, new List <string>() { navigProp }, out additionalInfos); string reqDataStr = reqData.ToString(); bool isMediaType = !string.IsNullOrEmpty(additionalInfos.Last().ODataMediaEtag); var resp = WebHelper.CreateEntity(url, context.RequestHeaders, reqData, isMediaType, ref additionalInfos); detail = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.Created == resp.StatusCode) { var mainEntityID = additionalInfos.Last().EntityId; string entityId = additionalInfos.First().EntityId; string refUrl = mainEntityID.TrimEnd('/') + "/" + navigProp + "/$ref"; string refEntitySetNameWithEnityID = entityId.Split('/').Last(); string refEntityValue = serviceStatus.RootURL.TrimEnd('/') + @"/" + refEntitySetNameWithEnityID; string refEntityID = refEntitySetNameWithEnityID.Contains("'") ? refEntitySetNameWithEnityID.Split('\'')[1] : refEntitySetNameWithEnityID.Split('(')[1].TrimEnd(')'); resp = WebHelper.GetEntity(mainEntityID); detail = new ExtensionRuleResultDetail(this.Name, mainEntityID, HttpMethod.Get, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.OK == resp.StatusCode && additionalInfos.Count > 1) { resp = WebHelper.GetEntity(refUrl); detail = new ExtensionRuleResultDetail(this.Name, refUrl, HttpMethod.Get, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.OK == resp.StatusCode) { JObject refPayload; resp.ResponsePayload.TryToJObject(out refPayload); bool created = false; if (navigRoughType == NavigationRoughType.CollectionValued) { var entries = JsonParserHelper.GetEntries(refPayload); if (entries != null) { foreach (JObject entry in entries) { foreach (JProperty prop in entry.Children()) { if (prop.Name.Equals(Constants.V4OdataId)) { created = prop.Value.ToString().Contains(refEntityID); if (created) { passed = true; break; } } } } } } else { foreach (JProperty prop in refPayload.Children()) { if (prop.Name.Equals(Constants.V4OdataId)) { created = prop.Value.ToString().Contains(refEntityID); if (created) { passed = true; break; } } } } if (!created) { passed = false; detail.ErrorMessage = string.Format("The HTTP deep insert failed to add a reference to a collection-valued navigation property failed."); } } } else { passed = false; detail.ErrorMessage = "Can not get the created entity. "; } // Restore the service. var resps = WebHelper.DeleteEntities(context.RequestHeaders, additionalInfos); } else { passed = false; detail.ErrorMessage = "Created the new entity failed for above URI. "; } var details = new List <ExtensionRuleResultDetail>() { detail }; info = new ExtensionRuleViolationInfo(new Uri(url), serviceStatus.ServiceDocument, details); return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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 serviceStatus = ServiceStatus.GetInstance(); var detail1 = new ExtensionRuleResultDetail(this.Name); var detail2 = new ExtensionRuleResultDetail(this.Name); var detail3 = new ExtensionRuleResultDetail(this.Name); string feedUrl = string.Empty; string entityUrl = string.Empty; KeyValuePair <string, IEnumerable <string> > entityUrls; if (JsonParserHelper.GetBatchSupportedEntityUrls(out entityUrls)) { feedUrl = string.Format("{0}/{1}", serviceStatus.RootURL, entityUrls.Key); entityUrl = entityUrls.Value.First(); } string relativeUrl = new Uri(entityUrl).LocalPath; string host = entityUrl.Remove(entityUrl.IndexOf(relativeUrl)); string format1Request = string.Format(@" --batch_36522ad7-fc75-4b56-8c71-56071383e77b Content-Type: application/http Content-Transfer-Encoding:binary GET {0} HTTP/1.1 --batch_36522ad7-fc75-4b56-8c71-56071383e77b--", entityUrl); string format2Request = string.Format(@" --batch_36522ad7-fc75-4b56-8c71-56071383e77b Content-Type: application/http Content-Transfer-Encoding:binary GET {0} HTTP/1.1 Host: {1} --batch_36522ad7-fc75-4b56-8c71-56071383e77b--", relativeUrl, host); string format3Reuqest = string.Format(@" --batch_36522ad7-fc75-4b56-8c71-56071383e77b Content-Type: application/http Content-Transfer-Encoding:binary GET {0} HTTP/1.1 --batch_36522ad7-fc75-4b56-8c71-56071383e77b--", relativeUrl); string boundary = @"batch_36522ad7-fc75-4b56-8c71-56071383e77b"; Response format1Response = WebHelper.BatchOperation(serviceStatus.RootURL.TrimEnd('/') + @"/", format1Request, boundary); detail1 = new ExtensionRuleResultDetail(this.Name, feedUrl + "/$batch", HttpMethod.Post, string.Empty, format1Response, string.Empty, format1Request); Response format2Response = WebHelper.BatchOperation(serviceStatus.RootURL.TrimEnd('/') + @"/", format2Request, boundary); detail2 = new ExtensionRuleResultDetail(this.Name, feedUrl + "/$batch", HttpMethod.Post, string.Empty, format2Response, string.Empty, format2Request); Response format3Response = WebHelper.BatchOperation(serviceStatus.RootURL.TrimEnd('/') + @"/", format3Reuqest, boundary); detail3 = new ExtensionRuleResultDetail(this.Name, feedUrl + "/$batch", HttpMethod.Post, string.Empty, format3Response, string.Empty, format3Reuqest); if (format1Response != null && !string.IsNullOrEmpty(format1Response.ResponsePayload)) { if (!format1Response.ResponsePayload.Contains(@"HTTP/1.1 200 OK")) { passed = false; detail1.ErrorMessage = string.Format("Batch request failed by above URI."); } } else { passed = false; detail1.ErrorMessage = "No response returned from above URI."; } if (format2Response != null && !string.IsNullOrEmpty(format2Response.ResponsePayload)) { if (!format2Response.ResponsePayload.Contains(@"HTTP/1.1 200 OK")) { passed = false; detail2.ErrorMessage = string.Format("Batch request failed by above URI and host : {0}. ", host); } } else { passed = false; detail2.ErrorMessage = string.Format("No response returned from above URI and host : {0}. ", host); } if (format3Response != null && !string.IsNullOrEmpty(format3Response.ResponsePayload)) { if (!format3Response.ResponsePayload.Contains(@"HTTP/1.1 200 OK")) { passed = false; detail3.ErrorMessage = string.Format("Batch request failed by above URI and Batch request host : {0}.", host); } } else { passed = false; detail3.ErrorMessage = string.Format("No response returned from above URI and Batch request host : {0}. ", host); } if (passed == null) { passed = true; } List <ExtensionRuleResultDetail> details = new List <ExtensionRuleResultDetail>() { detail1, detail2, detail3 }; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details); return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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; List <string> vocDocs = new List <string>() { context.VocCapabilities, context.VocCore, context.VocMeasures }; List <string> expectedTypes = new List <string>() { "Edm.String", "Edm.Int32", "Edm.Int16", "Edm.Single", "Edm.Double", "Edm.Boolean", "Edm.DateTimeOffset", "Edm.Guid" }; List <ExtensionRuleResultDetail> details = new List <ExtensionRuleResultDetail>(); ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name); var restrictions = new Dictionary <string, Tuple <List <NormalProperty>, List <NavigProperty> > >(); if (!AnnotationsHelper.GetExpandRestrictions(context.MetadataDocument, context.VocCapabilities, ref restrictions)) { detail.ErrorMessage = "Cannot find any appropriate entity-sets which supports $expand system query options."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } if (!AnnotationsHelper.IsSuitableNavigationProperty(NavigationRoughType.CollectionValued, ref restrictions)) { detail.ErrorMessage = "Cannot find any collection-valued navigation properties in any entity-sets which supports $expand system query options."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } string entitySet = string.Empty; string navigPropName = string.Empty; string primitivePropertyName = string.Empty; string primitivePropertyType = string.Empty; 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; } foreach (var np in r.Value.Item2) { string nEntityTypeShortName = np.NavigationPropertyType.RemoveCollectionFlag().GetLastSegment(); string nEntitySetName = nEntityTypeShortName.MapEntityTypeShortNameToEntitySetName(); var funcs = new List <Func <string, string, string, List <NormalProperty>, List <NavigProperty>, bool> >() { AnnotationsHelper.GetFilterRestrictions }; var rest = nEntitySetName.GetRestrictions(context.MetadataDocument, context.VocCapabilities, funcs, expectedTypes); if (string.IsNullOrEmpty(rest.Item1) || null == rest.Item2 || !rest.Item2.Any() || null == rest.Item3 || !rest.Item3.Any()) { continue; } navigPropName = np.NavigationPropertyName; primitivePropertyName = rest.Item2.First().PropertyName; primitivePropertyType = rest.Item2.First().PropertyType; break; } entitySet = r.Key; break; } if (string.IsNullOrEmpty(entitySet)) { detail.ErrorMessage = "Cannot find an appropriate entity-set which supports $expand system query option."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } if (string.IsNullOrEmpty(navigPropName)) { detail.ErrorMessage = "Cannot get expanded entities because cannot get collection type of navigation property from metadata"; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } if (string.IsNullOrEmpty(primitivePropertyName) || string.IsNullOrEmpty(primitivePropertyType)) { detail.ErrorMessage = "Cannot get an appropriate primitive property from navigation properties."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } string struri = string.Format("{0}/{1}?$expand={2}", context.ServiceBaseUri.OriginalString.TrimEnd('/'), entitySet, navigPropName); Uri uri = new Uri(struri); var response = WebHelper.Get(uri, Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); if (HttpStatusCode.OK != response.StatusCode) { passed = false; detail.ErrorMessage = JsonParserHelper.GetErrorMessage(response.ResponsePayload); info = new ExtensionRuleViolationInfo(uri, response.ResponsePayload, detail); return(passed); } JObject feed; response.ResponsePayload.TryToJObject(out feed); if (feed != null && JTokenType.Object == feed.Type) { var entities = JsonParserHelper.GetEntries(feed); var navigProp = entities[0][navigPropName] as JArray; if (navigProp != null && navigProp.Count != 0) { string propVal = navigProp[0][primitivePropertyName].ToString(); string compareVal = propVal; if (primitivePropertyType.Equals("Edm.String")) { compareVal = "'" + propVal + "'"; } string url = string.Format("{0}/{1}?$expand={2}($filter={3} eq {4})", context.ServiceBaseUri.OriginalString.TrimEnd('/'), entitySet, navigPropName, primitivePropertyName, compareVal); var resp = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); detail = new ExtensionRuleResultDetail(this.Name, url, "GET", StringHelper.MergeHeaders(Constants.AcceptHeaderJson, context.RequestHeaders), resp); if (resp.StatusCode == HttpStatusCode.OK) { JObject jObj; resp.ResponsePayload.TryToJObject(out jObj); if (jObj != null && JTokenType.Object == jObj.Type) { var entries = JsonParserHelper.GetEntries(jObj).ToList(); foreach (var entry in entries) { if (entry[navigPropName] != null && ((JArray)entry[navigPropName]).Count == 0) { continue; } else if (entry[navigPropName] != null && ((JArray)entry[navigPropName]).Count > 0) { var temp = entry[navigPropName].ToList() .FindAll(en => propVal == en[primitivePropertyName].ToString()) .Select(en => en); if (entry[navigPropName].ToList().Count == temp.Count()) { passed = true; } else { passed = false; detail.ErrorMessage = string.Format("The service does not execute an accurate result on system query option '$filter' (Actual Value: {0}, Expected Value: {1}).", entry[navigPropName].ToList().Count, temp.Count()); break; } } } } } else { passed = false; detail.ErrorMessage = string.Format("The service does not support system query option '$filter' on expanded entities."); } } } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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; ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name); var expandRestrictions = AnnotationsHelper.GetExpandRestrictions(context.MetadataDocument, context.VocCapabilities); if (string.IsNullOrEmpty(expandRestrictions.Item1) || null == expandRestrictions.Item3 || !expandRestrictions.Item3.Any()) { detail.ErrorMessage = "Cannot find an appropriate entity-set which supports $expand system query options."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } string entitySet = expandRestrictions.Item1; string navigProp = expandRestrictions.Item3.First().NavigationPropertyName; string url = string.Format("{0}/{1}", context.ServiceBaseUri, entitySet); var resp = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); if (null == resp || HttpStatusCode.OK != resp.StatusCode) { detail.ErrorMessage = JsonParserHelper.GetErrorMessage(resp.ResponsePayload); info = new ExtensionRuleViolationInfo(new Uri(url), resp.ResponsePayload, detail); return(passed); } JObject feed; resp.ResponsePayload.TryToJObject(out feed); var entities = JsonParserHelper.GetEntries(feed); if (null == entities || 0 == entities.Count) { detail.ErrorMessage = string.Format("The entity-set {0} has no entity.", entitySet); info = new ExtensionRuleViolationInfo(new Uri(url), resp.ResponsePayload, detail); return(passed); } var entity = entities.First; string entityURL = null != entity[Constants.V4OdataId] ? entity[Constants.V4OdataId].ToString() : string.Empty; if (string.IsNullOrEmpty(entityURL)) { detail.ErrorMessage = "Cannot find the annotation @odata.id in the current entity."; info = new ExtensionRuleViolationInfo(new Uri(url), resp.ResponsePayload, detail); return(passed); } url = string.Format("{0}?$expand={1}/$ref", entityURL, navigProp); resp = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); detail = new ExtensionRuleResultDetail(this.Name, url, "GET", StringHelper.MergeHeaders(Constants.AcceptHeaderJson, context.RequestHeaders), resp); if (resp.StatusCode == HttpStatusCode.OK) { JObject entry; resp.ResponsePayload.TryToJObject(out entry); if (entry != null && JTokenType.Object == entry.Type) { entity = entry[navigProp].First; url = entity[Constants.V4OdataId].ToString(); resp = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); if (resp.StatusCode == HttpStatusCode.OK) { passed = true; } else { passed = false; detail.ErrorMessage = "The service does not execute an accurate result, because the value of the annotation '@odata.id' is a bad link."; } } } else { passed = false; detail.ErrorMessage = "The service does not support the '$ref' segment for expanded properties."; } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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; List <ExtensionRuleResultDetail> details = new List <ExtensionRuleResultDetail>(); ExtensionRuleResultDetail detail1 = new ExtensionRuleResultDetail(this.Name); Tuple <string, List <NormalProperty>, List <NavigProperty> > filterRestrictions = null; try { filterRestrictions = AnnotationsHelper.GetFilterRestrictions(context.MetadataDocument, context.VocCapabilities); } catch { detail1.ErrorMessage = "The Metadata is malformed. Cannot determine the entity-set that supports $filter"; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1); passed = false; return(passed); } if (string.IsNullOrEmpty(filterRestrictions.Item1) || null == filterRestrictions.Item2 || !filterRestrictions.Item2.Any()) { detail1.ErrorMessage = "Cannot find an appropriate entity-set which supports $filter system query options in the service. Check for Malformed Metadata"; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1); return(passed); } string entitySet = filterRestrictions.Item1; string primitivePropName = filterRestrictions.Item2.First().PropertyName; string primitivePropType = filterRestrictions.Item2.First().PropertyType; string url = string.Format("{0}/{1}", context.ServiceBaseUri.OriginalString.TrimEnd('/'), entitySet); var resp = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); if (null == resp || HttpStatusCode.OK != resp.StatusCode) { detail1.ErrorMessage = JsonParserHelper.GetErrorMessage(resp.ResponsePayload); info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1); return(passed); } JObject feed; resp.ResponsePayload.TryToJObject(out feed); if (feed != null && JTokenType.Object == feed.Type) { var entities = JsonParserHelper.GetEntries(feed); string propVal = entities[0][primitivePropName].ToString(); #region Equal operation on filter. bool? isEqualOpValidation = null; string pattern = "Edm.String" == primitivePropType ? "{0}/{1}?$filter={2} eq '{3}'" : "{0}/{1}?$filter={2} eq {3}"; url = string.Format(pattern, context.ServiceBaseUri.OriginalString.TrimEnd('/'), entitySet, primitivePropName, propVal); resp = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); detail1 = new ExtensionRuleResultDetail(this.Name, url, "GET", StringHelper.MergeHeaders(Constants.AcceptHeaderJson, context.RequestHeaders), resp); if (resp.StatusCode == HttpStatusCode.OK) { JObject feed1; resp.ResponsePayload.TryToJObject(out feed1); if (feed1 != null && JTokenType.Object == feed1.Type) { var entities1 = JsonParserHelper.GetEntries(feed1).ToList(); var temp = entities1.FindAll(en => propVal == en[primitivePropName].ToString()).Select(en => en); if (entities1.Count() == temp.Count()) { isEqualOpValidation = true; } else { isEqualOpValidation = false; detail1.ErrorMessage = "The service does not execute an accurate result with system query option $filter eq."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1); return(isEqualOpValidation); } } } else { passed = false; detail1.ErrorMessage = "Request failed with system query option $filter eq."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1); return(passed); } #endregion #region NotEqual operation on filter. bool?isNotEqualOpValidation = null; pattern = "Edm.String" == primitivePropType ? "{0}/{1}?$filter={2} ne '{3}'" : "{0}/{1}?$filter={2} ne {3}"; url = string.Format(pattern, context.ServiceBaseUri.OriginalString.TrimEnd('/'), entitySet, primitivePropName, propVal); resp = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); ExtensionRuleResultDetail detail2 = new ExtensionRuleResultDetail(this.Name, url, "GET", StringHelper.MergeHeaders(Constants.AcceptHeaderJson, context.RequestHeaders), resp); if (resp.StatusCode == HttpStatusCode.OK) { JObject feed2; resp.ResponsePayload.TryToJObject(out feed2); if (feed2 != null && JTokenType.Object == feed2.Type) { var entities2 = JsonParserHelper.GetEntries(feed2).ToList(); var temp = entities2.FindAll(en => propVal != en[primitivePropName].ToString()).Select(en => en); if (entities2.Count() == temp.Count()) { isNotEqualOpValidation = true; } else { isNotEqualOpValidation = false; detail2.ErrorMessage = "The service does not execute an accurate result with system query option $filter ne."; } } } else { passed = false; detail2.ErrorMessage = "Request failed with system query option $filter ne."; } #endregion if (true == isEqualOpValidation && true == isNotEqualOpValidation) { passed = true; } details.Add(detail2); } details.Insert(0, detail1); info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, details); return(passed); }
/// <summary> /// Verify Common.Core.4719 /// </summary> /// <param name="context">Service context</param> /// <param name="info">out parameter 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"); } info = null; bool? passed = null; bool isActionProperty = false; string actionName = string.Empty; XElement metadata = XElement.Parse(context.MetadataDocument); JObject allobject; context.ResponsePayload.TryToJObject(out allobject); var jProps = allobject.Children(); // Use the XPath query language to access the metadata document to get all bound Action properties. // The bound action has IsBound as true and the first parameter with Type attribute equal to the entity type full name. string xpath = string.Format(@"//*[local-name()='Action' and @IsBound='true']/*[local-name()='Parameter' and position()=1 and @Type='{0}']/parent::*", context.EntityTypeFullName); List <string> boundActionNames = MetadataHelper.GetPropertyValues(context, xpath, "Name"); xpath = @"//*[local-name() = 'Schema'][1]"; XElement metadataSchema = metadata.XPathSelectElement(xpath, ODataNamespaceManager.Instance); if (boundActionNames.Count > 0) { foreach (JProperty jProp in jProps) { isActionProperty = JsonParserHelper.isFunctionOrActionProperty(boundActionNames, jProp, metadataSchema); // Whether the property is bound action property exist. if (isActionProperty) { if (jProp.Value["title"] != null && jProp.Value["target"] != null) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); break; } } } if (passed.HasValue && passed.Value == false) { return(false); } if (context.PayloadType == RuleEngine.PayloadType.Feed && allobject[Constants.Value] != null) { foreach (JObject ob in (JArray)allobject[Constants.Value]) { jProps = ob.Children(); foreach (JProperty jProp in jProps) { isActionProperty = JsonParserHelper.isFunctionOrActionProperty(boundActionNames, jProp, metadataSchema); // Whether the property is bound action property exist. if (isActionProperty) { if (jProp.Value["title"] != null && jProp.Value["target"] != null) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); break; } } } if (passed.HasValue && passed.Value == false) { break; } } } } return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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 serviceStatus = ServiceStatus.GetInstance(); string feedUrl = string.Empty; string entityUrl = string.Empty; KeyValuePair <string, IEnumerable <string> > entityUrls; if (JsonParserHelper.GetBatchSupportedEntityUrls(out entityUrls)) { feedUrl = string.Format("{0}/{1}", context.ServiceBaseUri, entityUrls.Key); entityUrl = entityUrls.Value.First(); } string relativeUrl = new Uri(entityUrl).LocalPath; string host = entityUrl.Remove(entityUrl.IndexOf(relativeUrl)); string batchRequest = string.Format(@" --batch_36522ad7-fc75-4b56-8c71-56071383e77b Content-Type: application/http Content-Transfer-Encoding:binary GET {0} HTTP/1.1 --batch_36522ad7-fc75-4b56-8c71-56071383e77b Content-Type: application/http Content-Transfer-Encoding:binary GET {0} HTTP/1.1 --batch_36522ad7-fc75-4b56-8c71-56071383e77b--", entityUrl); string boundary = @"batch_36522ad7-fc75-4b56-8c71-56071383e77b"; List <string> batchResponseSigns = new List <string>(); Response batchResponse = WebHelper.BatchOperation(context.ServiceBaseUri.OriginalString, batchRequest, boundary); var detail = new ExtensionRuleResultDetail(this.Name, context.ServiceBaseUri.OriginalString + "/$batch", HttpMethod.Post, string.Empty, batchResponse, string.Empty, batchRequest); if (batchResponse != null && !string.IsNullOrEmpty(batchResponse.ResponsePayload)) { string[] responseSegments = batchResponse.ResponsePayload.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); foreach (string seg in responseSegments) { if (seg.StartsWith(@"--batchresponse")) { batchResponseSigns.Add(seg); } } // The request has 3 batch separators if (batchResponseSigns.Count == 3) { passed = true; } else { passed = false; detail.ErrorMessage = string.Format("The batch response body does not match one-to-one with the batch request body, the batch request has 3 batch separators, but response has {0} batch separators. ", batchResponseSigns.Count); } } else { passed = false; detail.ErrorMessage = string.Format("Batch request failed: {0}.", batchRequest); } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); }
/// <summary> /// Verifies the service implementation feature. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if the service implementation feature passes; false otherwise</returns> public override bool?Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool?passed = null; ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name); info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); detail = info.Details[0]; List <string> supportedPropertyTypes = new List <string> { PrimitiveDataTypes.Int16, PrimitiveDataTypes.Int32, PrimitiveDataTypes.Int64, PrimitiveDataTypes.Decimal, PrimitiveDataTypes.Double }; var filterRestrictions = AnnotationsHelper.GetFilterRestrictionsWithoutNavi(context.MetadataDocument, context.VocCapabilities, supportedPropertyTypes); if (string.IsNullOrEmpty(filterRestrictions.Item1) || null == filterRestrictions.Item2 || !filterRestrictions.Item2.Any()) { detail.ErrorMessage = "Cannot find an appropriate entity-set which supports Greater Than system query options in the service."; return(passed); } string entitySet = filterRestrictions.Item1; string primitivePropName = filterRestrictions.Item2.First().PropertyName; string url = string.Format("{0}/{1}", context.ServiceBaseUri, entitySet); var resp = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); if (null == resp || HttpStatusCode.OK != resp.StatusCode) { detail.ErrorMessage = JsonParserHelper.GetErrorMessage(resp.ResponsePayload); return(passed); } JObject feed; resp.ResponsePayload.TryToJObject(out feed); if (feed == null || JTokenType.Object != feed.Type) { detail.ErrorMessage = "The service does not return a valid response for system query option"; return(passed); } var entities = JsonParserHelper.GetEntries(feed); Int64 propVal = entities[0].Value <Int64>(primitivePropName) - 1; string pattern = "{0}/{1}?$filter={2} gt {3}"; url = string.Format(pattern, context.ServiceBaseUri, entitySet, primitivePropName, propVal); resp = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); detail.URI = url; detail.HTTPMethod = "GET"; detail.RequestHeaders = StringHelper.MergeHeaders(Constants.AcceptHeaderJson, context.RequestHeaders); detail.ResponseStatusCode = resp != null && resp.StatusCode.HasValue ? resp.StatusCode.Value.ToString() : ""; detail.ResponseHeaders = string.IsNullOrEmpty(resp.ResponseHeaders) ? "" : resp.ResponseHeaders; detail.ResponsePayload = string.IsNullOrEmpty(resp.ResponsePayload) ? "" : resp.ResponsePayload; if (resp.StatusCode != HttpStatusCode.OK) { passed = false; detail.ErrorMessage = "Request failed with system query option $filter gt."; return(passed); } JObject feed2; resp.ResponsePayload.TryToJObject(out feed2); if (feed2 == null || JTokenType.Object != feed2.Type) { passed = false; detail.ErrorMessage = "The service does not return a valid response for system query option $filter gt."; return(passed); } var entities2 = JsonParserHelper.GetEntries(feed2).ToList(); var temp = entities2.FindAll(en => en.Value <Int64>(primitivePropName) > propVal).Select(en => en); if (entities2.Count() == temp.Count()) { passed = true; } else { passed = false; detail.ErrorMessage = "The service does not execute an accurate result with system query option $filter gt."; } return(passed); }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</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; ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name); var restrictions = new Dictionary <string, Tuple <List <NormalProperty>, List <NavigProperty> > >(); if (!AnnotationsHelper.GetExpandRestrictions(context.MetadataDocument, context.VocCapabilities, ref restrictions)) { detail.ErrorMessage = "Cannot find any appropriate entity-sets which supports $expand system query options."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } if (!AnnotationsHelper.IsSuitableNavigationProperty(NavigationRoughType.CollectionValued, ref restrictions)) { detail.ErrorMessage = "Cannot find any collection-valued navigation properties in any entity-sets which supports $expand system query options."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } string entitySet = string.Empty; string navigPropName = string.Empty; string primitivePropertyName = string.Empty; 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; } foreach (var np in r.Value.Item2) { string nEntityType = np.NavigationPropertyType.RemoveCollectionFlag().GetLastSegment(); var funcs = new List <Func <string, string, string, List <NormalProperty>, List <NavigProperty>, bool> >() { AnnotationsHelper.GetFilterRestrictions }; var expectedTypes = new List <string>() { "Edm.String" }; var props = MetadataHelper.GetNormalProperties(context.MetadataDocument, nEntityType); if (null == props || !props.Any()) { continue; } var targetProps = props.Where(p => expectedTypes.Contains(p.PropertyType)).Select(p => p); if (!targetProps.Any()) { continue; } navigPropName = np.NavigationPropertyName; primitivePropertyName = targetProps.First().PropertyName; break; } entitySet = r.Key; if (!string.IsNullOrEmpty(navigPropName) && !string.IsNullOrEmpty(primitivePropertyName)) { break; } } if (string.IsNullOrEmpty(entitySet)) { detail.ErrorMessage = "Cannot find an appropriate entity-set which supports $expand system query option."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } if (string.IsNullOrEmpty(navigPropName)) { detail.ErrorMessage = "Cannot get expanded entities because cannot get collection type of navigation property from metadata"; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } if (string.IsNullOrEmpty(primitivePropertyName)) { detail.ErrorMessage = "Cannot get an appropriate primitive property from navigation properties."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } string url = string.Format("{0}/{1}?$expand={2}", context.ServiceBaseUri, entitySet, navigPropName); var resp = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); if (null == resp || HttpStatusCode.OK != resp.StatusCode) { detail.ErrorMessage = JsonParserHelper.GetErrorMessage(resp.ResponsePayload); info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } JObject feed; resp.ResponsePayload.TryToJObject(out feed); var entities = JsonParserHelper.GetEntries(feed); if (null == entities || !entities.Any()) { detail.ErrorMessage = string.Format("Cannot find any entities from the entity-set '{0}'", entitySet); info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } string searchVal = string.Empty; foreach (var en in entities) { if (null != en[navigPropName] || JTokenType.Array == en[navigPropName].Type || en[navigPropName].Any()) { if (JTokenType.Object != en[navigPropName].First.Type) { break; } var nEntity = en[navigPropName].First as JObject; searchVal = nEntity[primitivePropertyName].ToString().Contains(" ") ? string.Format("\"{0}\"", nEntity[primitivePropertyName].ToString()) : nEntity[primitivePropertyName].ToString(); if (!string.IsNullOrEmpty(searchVal)) { break; } } } if (string.IsNullOrEmpty(searchVal)) { detail.ErrorMessage = "Cannot find any appropriate search values in the expanded entities."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); } url = string.Format("{0}/{1}?$expand={2}($search={3})", context.ServiceBaseUri, entitySet, navigPropName, searchVal); resp = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); detail = new ExtensionRuleResultDetail(this.Name, url, "GET", String.Empty, resp); if (null != resp && resp.StatusCode == HttpStatusCode.OK) { resp.ResponsePayload.TryToJObject(out feed); if (null != feed && JTokenType.Object == feed.Type) { entities = JsonParserHelper.GetEntries(feed); foreach (var e in entities) { var navigEntities = e[navigPropName].ToList(); if (null == navigEntities || !navigEntities.Any()) { continue; } foreach (var ne in navigEntities) { passed = null; if (searchVal.StripOffDoubleQuotes() == ne[primitivePropertyName].ToString()) { passed = true; } if (passed == null) { passed = false; detail.ErrorMessage = "The service does not execute an accurate result on the system query option '$search' for expanded properties."; } } if (passed == false) { break; } } if (null == passed) { detail.ErrorMessage = "Cannot find any appropriate data to verify this rule."; } } else { detail.ErrorMessage = "The service does not return an correct response payload."; } } else { passed = false; detail.ErrorMessage = "The service does not support the system query option '$search' for expanded properties."; } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return(passed); }