/// <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> /// 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 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> /// 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 Common.Core.4623 /// </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; // Single primitive individual property is not allowed to have instance annotation. if (VerificationHelper.IsIndividualPropertySinglePrimitiveType(context.ResponsePayload, context.PayloadType)) { return(null); } XmlDocument xmlDoc = new XmlDocument(); // 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["null", Constants.NSMetadata] != null && annotatEle.Attributes["null", Constants.NSMetadata].Value.Equals("true")) { return(null); } string content = annotatEle.InnerText; 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)) { IEdmType edmType = EdmTypeManager.GetEdmType(typeName); if (edmType.IsGoodWith(content)) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); 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); }