/// <summary> /// Verify Metadata.Core.4234 /// </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; // Load MetadataDocument into XMLDOM XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(context.MetadataDocument); XmlNodeList typeDefNodeList = xmlDoc.SelectNodes("//*[local-name()='TypeDefinition']"); foreach (XmlNode typeDef in typeDefNodeList) { if (typeDef.Attributes["UnderlyingType"] != null && EdmTypeManager.IsEdmSimpleType(typeDef.Attributes["UnderlyingType"].Value)) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); break; } } return(passed); }
/// <summary> /// Construct a complex type value according to its metadata definition. /// </summary> /// <param name="complexName">The name of the complex type.</param> /// <returns>The JSON object value of the complex type.</returns> public JObject ConstructAComplexTypeValue(string complexName) { string metadataDoc = ServiceStatus.GetInstance().MetadataDocument; JObject result = new JObject(); List <string> complextTypeNames = MetadataHelper.GetAllComplexNameFromMetadata(metadataDoc); Dictionary <string, string> properties = MetadataHelper.GetAllPropertiesOfComplexType(metadataDoc, complexName); foreach (string prop in properties.Keys) { string type = properties[prop]; if (EdmTypeManager.IsEdmSimpleType(type)) { IEdmType edmType = EdmTypeManager.GetEdmType(type); result[prop] = edmType.GetJsonValueTemplate(); } else if (type.Contains("Collection")) { string itemType = type.Substring(type.IndexOf('(') + 1, type.Length - 12).GetLastSegment(); result[prop] = ConstructCollectionTypeValue(itemType); } else if (MetadataHelper.IsEnumType(metadataDoc, type)) { result[prop] = ConstructEnumTypeValue(type); } else if (complextTypeNames != null && complextTypeNames.Contains(type)) { result[prop] = ConstructAComplexTypeValue(type); } } return(result); }
/// <summary> /// Verify IndividualProperty.Core.4607 /// </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; XmlDocument xmlDoc = new XmlDocument(); // Test Data // 1. Collection of string. Url:http://services.odata.org/V4/OData/OData.svc/Products(0)/Description?$format=xml // xmlDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><m:value m:context=\"http://services.odata.org/V4/OData/OData.svc/$metadata#Collection(Edm.String)\" xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" xmlns:georss=\"http://www.georss.org/georss\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"><m:element>Whole grain</m:element> <m:element>bread</m:element></m:value>"); // 2. Collection of complext type. Url: http://services.odata.org/V4/OData/OData.svc/PersonDetails(0)/Address?$format=xml // xmlDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><m:value m:context=\"http://services.odata.org/V4/OData/OData.svc/$metadata#Collection(ODataDemo.Address)\" m:type=\"#Collection(ODataDemo.Address)\" xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" xmlns:georss=\"http://www.georss.org/georss\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"><m:element><d:Street>2817 Milton Dr.</d:Street><d:City>Albuquerque</d:City><d:State>NM</d:State><d:ZipCode>87110</d:ZipCode><d:Country>USA</d:Country></m:element><m:element><d:Street>2817 Milton Dr.</d:Street><d:City>Detorlee</d:City><d:State>UT</d:State><d:ZipCode>124450</d:ZipCode><d:Country>USA</d:Country></m:element></m:value>"); // Metadata: modify PersonDatail 's Address Type to Collection(ODataDemo.Address) xmlDoc.LoadXml(context.ResponsePayload); XmlElement root = xmlDoc.DocumentElement; if (root.LocalName.Equals("value") && root.NamespaceURI.Equals(Constants.NSMetadata)) { if (root.Attributes["context", Constants.NSMetadata] != null) { string contextURI = root.Attributes["context", Constants.NSMetadata].Value; string propertyTypeCol = contextURI.Remove(0, contextURI.IndexOf('#') + 1); if (!propertyTypeCol.Contains("Collection(")) { return(null); } string propertyType = propertyTypeCol.Substring(propertyTypeCol.IndexOf('(') + 1, propertyTypeCol.Length - 12); string propertyTypeShortName = propertyType.GetLastSegment(); var metadata = XElement.Parse(context.MetadataDocument); // Built-in primitive types. if (propertyType.Contains("Edm.") && EdmTypeManager.IsEdmSimpleType(propertyType)) { return(true); } // Complex type. List <string> complextTypes = MetadataHelper.GetAllComplexNameFromMetadata(context.MetadataDocument); if (complextTypes.Contains(propertyTypeShortName)) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); } } } return(passed); }
/// <summary> /// Provide the value tempalte of a collection. /// </summary> /// <param name="type">The name of the collection content type.</param> /// <returns>The JSON array of the collection.</returns> public JArray ConstructCollectionTypeValue(string type) { string metadataDoc = ServiceStatus.GetInstance().MetadataDocument; JArray array = new JArray(); List <string> complextTypeNames = MetadataHelper.GetAllComplexNameFromMetadata(metadataDoc); if (EdmTypeManager.IsEdmSimpleType(type)) { string value = ConstructPrimitiveTypeValue(type); array.Add(value); array.Add(value); } else if (complextTypeNames != null && complextTypeNames.Count > 0 && complextTypeNames.Contains(type)) { JObject objValue = ConstructAComplexTypeValue(type); array.Add(objValue); array.Add(objValue); } else if (MetadataHelper.IsEnumType(metadataDoc, type)) { array.Add(ConstructEnumTypeValue(type)); array.Add(ConstructEnumTypeValue(type)); } return(array); }
/// <summary> /// Get property type and type class. /// </summary> /// <param name="entityTypeShortName"> The short name of entity type.</param> /// <param name="propertyName">The name of the property in the entity type.</param> /// <returns>The key value pair in which key is the property type short name and the value is the property type class.</returns> private KeyValuePair <string, PropertyTypeClass>?GetPropertyTypeClass(string entityTypeShortName, string propertyName) { string pattern = "//*[local-name()='EntityType' and @Name='{0}']/*[local-name()='Property' and @Name='{1}']"; string metadataString = ServiceStatus.GetInstance().MetadataDocument; var metadata = XElement.Parse(metadataString); string xPath = string.Format(pattern, entityTypeShortName, propertyName); XElement prop = metadata.XPathSelectElement(xPath, ODataNamespaceManager.Instance); if (prop == null) { return(null); } string propType = prop.GetAttributeValue("Type"); string propTypeShortName = propType.RemoveCollectionFlag().GetLastSegment(); PropertyTypeClass typeClass = PropertyTypeClass.Unknown; string type = propTypeShortName; if (propType.Contains("Collection(")) { typeClass = PropertyTypeClass.CollectionType; } else if (EdmTypeManager.IsEdmSimpleType(propType)) { typeClass = PropertyTypeClass.PrimitiveType; type = propType; } else { xPath = string.Format("//*[@Name = '{0}']", propTypeShortName); XElement typeDefElement = metadata.XPathSelectElement(xPath, ODataNamespaceManager.Instance); if (typeDefElement == null) { return(null); } switch (typeDefElement.Name.LocalName) { case "ComplexType": typeClass = PropertyTypeClass.ComplexType; break; case "EnumType": typeClass = PropertyTypeClass.EnumType; break; default: typeClass = PropertyTypeClass.Unknown; break; } } return(new KeyValuePair <string, PropertyTypeClass>(type, typeClass)); }
/// <summary> /// Verify Entry.Core.2018 /// </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; // Load MetadataDocument into XMLDOM XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(context.MetadataDocument); // Get all the properties XmlNodeList propertyNodeList = xmlDoc.SelectNodes("//*[local-name()='EntityType' and @Name = '" + context.EntityTypeShortName + "']/*[local-name()='Property']"); List <string> complexTypeProperties = new List <string>(); // Get all Complex Type properties foreach (XmlNode node in propertyNodeList) { if (!EdmTypeManager.IsEdmSimpleType(node.Attributes["Type"].Value)) { complexTypeProperties.Add(node.Attributes["Type"].Value); } } if (complexTypeProperties.Count > 0) { var complexTypePropertyList = complexTypeProperties.GroupBy(c => c); XmlDocument xmlDoc2 = new XmlDocument(); xmlDoc2.LoadXml(context.ResponsePayload); XmlNodeList nodeList; // Verify that all Complex Type properties are represent under m:properties foreach (var complexTypeProperty in complexTypePropertyList) { nodeList = xmlDoc2.SelectNodes("//*[@*[local-name()='type'] = '" + complexTypeProperty.Key + "']"); if (nodeList.Count == complexTypeProperty.Count()) { passed = true; } else { passed = false; break; } } } info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); return(passed); }
/// <summary> /// Verify Common.Core.4624 /// </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; XmlDocument xmlDoc = new XmlDocument(); // Single primitive individual property is not allowed to have instance annotation. if (VerificationHelper.IsIndividualPropertySinglePrimitiveType(context.ResponsePayload, context.PayloadType)) { return(null); } // Test Data // Url:http://services.odata.org/V4/OData/OData.svc/Products(0)/Description?$format=xml // xmlDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><m:value m:context=\"http://services.odata.org/V4/OData/OData.svc/$metadata#Products(0)/Description\" xmlns:atom=\"http://www.w3.org/2005/Atom\" xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" xmlns:georss=\"http://www.georss.org/georss\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\">Whole grain bread <m:annotation atom:term=\"ODataDemo.Product.Display\" m:target=\"Description\" m:type=\"Boolean\">true</m:annotation></m:value>"); xmlDoc.LoadXml(context.ResponsePayload); XmlNodeList annotationElements = xmlDoc.SelectNodes(@"//*[local-name()='annotation']", ODataNamespaceManager.Instance); foreach (XmlNode annotatEle in annotationElements) { if (annotatEle.Attributes["type", Constants.NSMetadata] != null) { string typeName = annotatEle.Attributes["type", Constants.NSMetadata].Value; if (!typeName.Contains(".")) { typeName = "Edm." + typeName; } if (!EdmTypeManager.IsEdmSimpleType(typeName)) { continue; } if (typeName != "Edm.String") { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); break; } } } return(passed); }
/// <summary> /// Provide value template for a primitive type. /// </summary> /// <param name="type">The primitive type name.</param> /// <returns>The template value of the primitive type.</returns> public string ConstructPrimitiveTypeValue(string type) { if (EdmTypeManager.IsEdmSimpleType(type)) { IEdmType edmType = EdmTypeManager.GetEdmType(type); return(edmType.GetJsonValueTemplate()); } return(null); }
/// <summary> /// Verify the code rule /// </summary> /// <param name="context">Service context</param> /// <param name="info">out paramater to return violation information when rule fail</param> /// <returns>true if rule passes; false otherwise</returns> public override bool?Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool?passed = null; info = null; var segments = ResourcePathHelper.GetPathSegments(context).ToArray(); var edmxHelper = new EdmxHelper(XElement.Parse(context.MetadataDocument)); UriType uriType; var target = edmxHelper.GetTargetType(segments, out uriType); if (uriType == UriType.URI4 || uriType == UriType.URI5) { passed = false; string targetType = ((EdmProperty)target).TypeUsage.EdmType.FullName; string property = segments.LastOrDefault(s => !s.StartsWith("$")); JObject jo = JObject.Parse(context.ResponsePayload); var inner = jo.ReachInnerToken(); if (inner.Type == JTokenType.Object) { JObject innerObj = (JObject)inner; if (innerObj.Properties() != null && innerObj.Properties().Count() == 1) { var value = innerObj.Properties().First().Value; string valueLiteral = value.ToString(); IEdmType type = EdmTypeManager.GetEdmType(targetType); bool isValidJsonData = type.IsGoodInJsonWith(valueLiteral); if (isValidJsonData) { passed = true; } else { // target type may allow null //TODO: allow null only when the target type is nullable passed = valueLiteral.Equals("null", StringComparison.Ordinal); } } } } if (passed.HasValue && !passed.Value) { info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload, -1); } return(passed); }
/// <summary> /// Verify rule logic /// </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; // Load MetadataDocument into XMLDOM XmlDocument mdDoc = new XmlDocument(); mdDoc.LoadXml(context.MetadataDocument); // Load payload into XMLDOM and find all properties marked m:null as true XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(context.ResponsePayload); XmlNodeList nullPropertyList = xmlDoc.SelectNodes("//*[@*[name()='m:null'] = 'true']"); XmlNode propertyNode; foreach (XmlNode node in nullPropertyList) { if (node.ParentNode.LocalName.Equals("properties", StringComparison.InvariantCultureIgnoreCase)) { propertyNode = mdDoc.SelectSingleNode("//*[local-name()='EntityType' and @Name = '" + context.EntityTypeShortName + "']/*[local-name()='Property' and @Name = '" + node.LocalName + "']"); } else { var tempNode = mdDoc.SelectSingleNode("//*[local-name()='EntityType' and @Name = '" + context.EntityTypeShortName + "']/*[local-name()='Property' and @Name = '" + node.ParentNode.LocalName + "']"); propertyNode = mdDoc.SelectSingleNode("//*[local-name()='ComplexType' and @Name = '" + tempNode.Attributes["Type"].Value.Split('.').Last() + "']/*[local-name()='Property' and @Name = '" + node.LocalName + "']"); } if (node.InnerText == "") { if (EdmTypeManager.IsEdmSimpleType(propertyNode.Attributes["Type"].Value)) { passed = true; } else { passed = false; break; } } } info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); return(passed); }
/// <summary> /// Verify Metadata.Core.2013 /// </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; // Load MetadataDocument into XMLDOM XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(context.MetadataDocument); // Find all EntityType nodes XmlNodeList xmlNodeList = xmlDoc.SelectNodes("//*/*[local-name()='EntityType']"); foreach (XmlNode entityTypeNode in xmlNodeList) { if (entityTypeNode.Attributes["m:FC_TargetPath"] != null) { if (entityTypeNode.Attributes["m:FC_SourcePath"] != null) { string typeName = entityTypeNode.Attributes["m:FC_SourcePath"].Value.Split('/').Last(); XmlNode node = entityTypeNode.SelectSingleNode("//*[local-name()='Property' and @Name = '" + typeName + "']"); if (EdmTypeManager.IsEdmSimpleType(node.Attributes["Type"].Value)) { passed = false; break; } else { passed = true; } } else { passed = false; break; } } } info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); return(passed); }
/// <summary> /// Verify the code rule /// </summary> /// <param name="context">Service context</param> /// <param name="info">out paramater to return violation information when rule fail</param> /// <returns>true if rule passes; false otherwise</returns> public override bool?Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool?passed = null; info = null; var segments = ResourcePathHelper.GetPathSegments(context).ToArray(); if (segments.Length > 0) { string lastSeg = segments[segments.Length - 1]; if (lastSeg.Equals("$value", StringComparison.Ordinal)) { var edmxHelper = new EdmxHelper(XElement.Parse(context.MetadataDocument)); UriType uriType; var target = edmxHelper.GetTargetType(segments, out uriType); if (uriType == UriType.URI4 || uriType == UriType.URI5) { string targetType = ((EdmProperty)target).TypeUsage.EdmType.FullName; if (!string.IsNullOrEmpty(targetType)) { // do the validation here IEdmType type = EdmTypeManager.GetEdmType(targetType); if (type != null) { passed = type.IsGoodWith(context.ResponsePayload); if (passed.HasValue && !passed.Value) { info = new ExtensionRuleViolationInfo("pattern not matched", context.Destination, context.ResponsePayload, 1); } } else { // type unknown info = new ExtensionRuleViolationInfo("unrecognized Edm type", context.Destination, targetType, 1); passed = false; } } } } } return(passed); }
/// <summary> /// Checks whether the value is well-formatted based on the type /// </summary> /// <param name="value">The value</param> /// <param name="typeName">Name of the type</param> /// <returns>bool indicating value being well-formatted</returns> protected bool VerifyValueByPrimitiveType(string value, string typeName) { bool result = true; if (!string.IsNullOrEmpty(value)) { IEdmType type = EdmTypeManager.GetEdmType(typeName); if (type == null) { //unrecognized primitive type result = false; } else { result = type.IsGoodWith(value); } } return(result); }
/// <summary> /// Verify Metadata.Core.4076 /// </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; XmlDocument metadata = new XmlDocument(); metadata.LoadXml(context.MetadataDocument); string xpath = @"/*[local-name()='Edmx']/*[local-name()='DataServices']/*[local-name()='Schema']/*[local-name()='EntityType' or local-name()='ComplexType']/*[local-name()='Property']"; XmlNodeList propertyCollection = metadata.SelectNodes(xpath, ODataNamespaceManager.Instance); foreach (XmlNode property in propertyCollection) { if (property.Attributes["Precision"] == null || (property.Attributes["Type"] != null && !EdmTypeManager.IsTemporalTypeName(property.Attributes["Type"].Value)) ) { continue; } int precision; if (Int32.TryParse(property.Attributes["Precision"].Value, out precision) && precision >= 0 && precision < 12) { passed = true; } else { passed = false; break; } } info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); return(passed); }
/// <summary> /// Verify Entry.Core.2018 /// </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; // Load MetadataDocument into XMLDOM XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(context.MetadataDocument); XmlNode keyNode = xmlDoc.SelectSingleNode("//*[local-name()='EntityType' and @Name = '" + context.EntityTypeShortName + "']/*[local-name()='Key']"); if (keyNode != null) { foreach (XmlNode node in keyNode.ChildNodes) { XmlNode propertyNode = xmlDoc.SelectSingleNode("//*[local-name()='EntityType' and @Name = '" + context.EntityTypeShortName + "']/*[local-name()='Property' and @Name='" + node.Attributes["Name"].Value + "']"); if (EdmTypeManager.IsEdmSimpleType(propertyNode.Attributes["Type"].Value)) { passed = true; } else { passed = false; break; } } } info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); return(passed); }
/// <summary> /// Verify Metadata.Core.2017 /// </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; // Load MetadataDocument into XMLDOM XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(context.MetadataDocument); // Find all Proeprty nodes with ConcurrencyMode = "Fixed" XmlNodeList propertyNodeList = xmlDoc.SelectNodes("//*[@*[name()='ConcurrencyMode'] = 'Fixed']"); if (propertyNodeList.Count != 0) { foreach (XmlNode propertyNode in propertyNodeList) { if (EdmTypeManager.IsEdmSimpleType(propertyNode.Attributes["Type"].Value)) { passed = true; } else { passed = false; break; } } } info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); return(passed); }
/// <summary> /// Verify IndividualProperty.Core.4606 /// </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; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(context.ResponsePayload); XmlElement root = xmlDoc.DocumentElement; XElement metadata = XElement.Parse(context.MetadataDocument); string xpath = string.Empty; string individualPropType = string.Empty; string entityTypeShortName = string.Empty; if (root.LocalName.Equals("value") && root.NamespaceURI.Equals(Constants.NSMetadata)) { if (root.Attributes["context", Constants.NSMetadata] != null) { string contextURI = root.Attributes["context", Constants.NSMetadata].Value; string propertyType = contextURI.Remove(0, contextURI.IndexOf('#') + 1); if (propertyType.Contains("Collection(")) { return(null); } string[] types = propertyType.Split('/'); if (types.Length == 2) { if (types[0].Contains("(")) { string entitySetName = types[0].Remove(types[0].IndexOf('(')); entityTypeShortName = entitySetName.MapEntitySetNameToEntityTypeShortName(); } else { xpath = string.Format(@"//*[local-name()='Singleton' and @Name='{0}']", types[0]); XElement singleton = metadata.XPathSelectElement(xpath, ODataNamespaceManager.Instance); entityTypeShortName = singleton.GetAttributeValue("Type").GetLastSegment(); } individualPropType = MetadataHelper.GetPropertyTypeFromMetadata(types[1], entityTypeShortName, context.MetadataDocument); } else if (types.Length < 2) { individualPropType = propertyType; } if (!individualPropType.Equals("Edm.String")) { xpath = @"//*[local-name()='DataServices']/*[local-name()='Schema']"; List <string> qualitifiedNamespaces = MetadataHelper.GetPropertyValues(context, xpath, "Namespace"); List <string> qualitifiedAliases = MetadataHelper.GetPropertyValues(context, xpath, "Alias"); if (root.Attributes["type", Constants.NSMetadata] != null) { string typeName = root.Attributes["type", Constants.NSMetadata].Value; if (!typeName.Contains(".")) { typeName = "Edm." + typeName; } if ((this.IsContainsSpecialStrings(qualitifiedNamespaces, typeName) || this.IsContainsSpecialStrings(qualitifiedAliases, typeName)) || EdmTypeManager.IsEdmSimpleType(typeName)) { passed = true; } else { 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> /// Verify Metadata.Core.4486 /// </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; string mergedMetadata = context.ContainsExternalSchema ? context.MergedMetadataDocument : context.MetadataDocument; XmlDocument xmlDoc_MergedMetadata = new XmlDocument(); xmlDoc_MergedMetadata.LoadXml(mergedMetadata); // Load MetadataDocument into XMLDOM XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(context.MetadataDocument); List <XmlNode> NvPropNodeList = new List <XmlNode>(); XmlNodeList NodeList = xmlDoc.SelectNodes("//*[local-name()='PropertyPath']"); XmlNodeList AttributeNodeList = xmlDoc.SelectNodes("//*[@PropertyPath]"); foreach (XmlNode NvProp in AttributeNodeList) { NvPropNodeList.Add(NvProp); } foreach (XmlNode NvProp in NodeList) { NvPropNodeList.Add(NvProp); } foreach (XmlNode NvPropPath in NvPropNodeList) { string path; if (NvPropPath.Attributes["PropertyPath"] != null) { path = NvPropPath.Attributes["PropertyPath"].Value; } else { path = NvPropPath.InnerText; } XmlNode parentOrTarget = NvPropPath; while (!parentOrTarget.LocalName.Equals("Annotation") && parentOrTarget.ParentNode != null) { parentOrTarget = parentOrTarget.ParentNode; } parentOrTarget = parentOrTarget.ParentNode; if (parentOrTarget.LocalName.Equals("Annotations")) { string parentTargetPath = parentOrTarget.Attributes["Target"].Value; parentOrTarget = parentOrTarget.ParentNode; if (MetadataHelper.Path(parentTargetPath, xmlDoc_MergedMetadata, context, ref parentOrTarget)) { // For annotations targeting a property of an entity type or complex type, // the path expression is evaluated starting at the outermost entity type or complex type // named in the Target of the enclosing edm:Annotations element. if (parentOrTarget.LocalName.Equals("Property") || parentOrTarget.LocalName.Equals("NavigationProperty")) { while (!(parentOrTarget.LocalName.Equals("EntityType") || parentOrTarget.LocalName.Equals("ComplexType"))) { parentOrTarget = parentOrTarget.ParentNode; } } XmlNode resolveNode = parentOrTarget; if (MetadataHelper.Path(path, xmlDoc_MergedMetadata, context, ref resolveNode)) { if (resolveNode.LocalName.Equals("Property")) { passed = true; } else if (resolveNode.LocalName.Equals("Term")) { if (resolveNode.Attributes["Type"].Value.RemoveCollectionFlag().Equals("Edm.ComplexType") || resolveNode.Attributes["Type"].Value.RemoveCollectionFlag().Equals("Edm.PrimitiveType")) { passed = true; } else if (EdmTypeManager.IsEdmSimpleType(resolveNode.Attributes["Type"].Value.RemoveCollectionFlag())) { passed = true; } else { string type = resolveNode.Attributes["Type"].Value.RemoveCollectionFlag(); XElement termTypeEle; termTypeEle = MetadataHelper.GetTypeDefinitionEleInScope(@"ComplexType' or 'EnumType' or 'TypeDefinition", type, context); if (termTypeEle != null) { passed = true; } else { info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); passed = false; break; } } } } } } else { XmlNode resolveNode = parentOrTarget; if (MetadataHelper.Path(path, xmlDoc_MergedMetadata, context, ref resolveNode)) { if (resolveNode.LocalName.Equals("Property")) { passed = true; } else if (resolveNode.LocalName.Equals("Term")) { if (resolveNode.Attributes["Type"].Value.RemoveCollectionFlag().Equals("Edm.ComplexType") || resolveNode.Attributes["Type"].Value.RemoveCollectionFlag().Equals("Edm.PrimitiveType")) { passed = true; } else if (EdmTypeManager.IsEdmSimpleType(resolveNode.Attributes["Type"].Value.RemoveCollectionFlag())) { passed = true; } else { string type = resolveNode.Attributes["Type"].Value.RemoveCollectionFlag(); XElement termTypeEle; termTypeEle = MetadataHelper.GetTypeDefinitionEleInScope(@"ComplexType' or 'EnumType' or 'TypeDefinition", type, context); if (termTypeEle != null) { passed = true; } else { info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); passed = false; break; } } } } } } return(passed); }
/// <summary> /// Verify Metadata.Core.4228 /// </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; // Load MetadataDocument into XMLDOM XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(context.MetadataDocument); string xpath = "//*[local-name()='EnumType']"; XmlNodeList enumTypeNodeList = xmlDoc.SelectNodes(xpath); foreach (XmlNode enumType in enumTypeNodeList) { string underlyingType = string.Empty; if (enumType.Attributes["UnderlyingType"] != null) { underlyingType = enumType.Attributes["UnderlyingType"].Value; } else { underlyingType = "Edm.Int32"; } foreach (XmlNode member in enumType.ChildNodes) { if (!member.Name.Equals("Member")) { continue; } else { if (member.Attributes["Value"] != null) { IEdmType edmType = EdmTypeManager.GetEdmType(underlyingType); if (edmType.IsGoodWith(member.Attributes["Value"].Value)) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); break; } } } } if (passed == false) { break; } } return(passed); }
/// <summary> /// Verify IndividualProperty.Core.4610 /// </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; XmlDocument xmlDoc = new XmlDocument(); // Test Data // 1. Collection of string. Url:http://services.odata.org/V4/OData/OData.svc/Products(0)/Description?$format=xml // xmlDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><m:value m:context=\"http://services.odata.org/V4/OData/OData.svc/$metadata#Collection(Edm.String)\" xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" xmlns:georss=\"http://www.georss.org/georss\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"><m:element>Whole grain</m:element> <m:element>bread</m:element></m:value>"); // 2. Collection of complext type. Url: http://services.odata.org/V4/OData/OData.svc/PersonDetails(0)/Address?$format=xml // xmlDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\"?><m:value m:context=\"http://services.odata.org/V4/OData/OData.svc/$metadata#Collection(ODataDemo.Address)\" m:type=\"#Collection(ODataDemo.Address)\" xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" xmlns:georss=\"http://www.georss.org/georss\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"><m:element><d:Street>2817 Milton Dr.</d:Street><d:City>Albuquerque</d:City><d:State>NM</d:State><d:ZipCode>87110</d:ZipCode><d:Country>USA</d:Country></m:element><m:element><d:Street>2817 Milton Dr.</d:Street><d:City>Detorlee</d:City><d:State>UT</d:State><d:ZipCode>124450</d:ZipCode><d:Country>USA</d:Country></m:element></m:value>"); xmlDoc.LoadXml(context.ResponsePayload); XmlElement root = xmlDoc.DocumentElement; if (root.LocalName.Equals("value") && root.NamespaceURI.Equals(Constants.NSMetadata)) { if (root.Attributes["context", Constants.NSMetadata] != null) { string contextURL = root.Attributes["context", Constants.NSMetadata].Value; string propertyTypeCol = contextURL.Remove(0, contextURL.IndexOf('#') + 1); if (!propertyTypeCol.Contains("Collection(")) { return(null); } string propertyTypeFullName = propertyTypeCol.Substring(propertyTypeCol.IndexOf('(') + 1, propertyTypeCol.Length - 12); string propertyTypeShortName = propertyTypeFullName.GetLastSegment(); // Verify whether the context URL is a valid url. if (!Uri.IsWellFormedUriString(contextURL, UriKind.Absolute)) { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); return(passed); } string metadataUrl = contextURL.Remove(contextURL.IndexOf('#')); var resp = WebHelper.Get(new Uri(metadataUrl), Constants.AcceptHeaderAtom, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); if (null != resp && HttpStatusCode.OK == resp.StatusCode) { var metadata = XElement.Parse(resp.ResponsePayload); if (null != metadata && "Edmx" == metadata.Name.LocalName) { passed = false; if (propertyTypeFullName.Contains("Edm.") && EdmTypeManager.IsEdmSimpleType(propertyTypeFullName)) { return(true); } string xpath = string.Format(@"//*[local-name()='ComplexType' and @Name='{0}']", propertyTypeShortName); XElement complexType = metadata.XPathSelectElement(xpath, ODataNamespaceManager.Instance); if (complexType != null) { return(true); } } if (passed == false) { info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); } } } } return(passed); }