/// <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; // Verify the lambda operator "any". HttpStatusCode? statusCode1 = VerificationHelper.VerifyLambdaOperators(context, LambdaOperatorType.Any, out passed, out info); if (true != passed) { if (info != null) { info.SetDetailsName(this.Name); } return passed; } // Verify the lambda operator "all". HttpStatusCode? statusCode2 = VerificationHelper.VerifyLambdaOperators(context, LambdaOperatorType.All, out passed, out info); if (info != null) { info.SetDetailsName(this.Name); } 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; HttpStatusCode? statusCode1 = VerificationHelper.VerifyCanonicalFunction(context, CanonicalFunctionType.Supported, out passed, out info); if (true != passed) { if (info != null) { info.SetDetailsName(this.Name); } return passed; } HttpStatusCode? statusCode2 = VerificationHelper.VerifyCanonicalFunction(context, CanonicalFunctionType.Unsupported, out passed, out info); passed = statusCode2 == HttpStatusCode.NotImplemented ? true : false; if (info != null) { info.SetDetailsName(this.Name); } 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"); } info = null; List<ExtensionRuleResultDetail> details = new List<ExtensionRuleResultDetail>(); ExtensionRuleViolationInfo info1 = null, info2 = null; bool? isVerifySortEntitiesOrderByAsc = VerificationHelper.VerifySortEntities(context, SortedType.ASC, out info1); bool? isVerifySortEntitiesOrderByDesc = VerificationHelper.VerifySortEntities(context, SortedType.DESC, out info2); if (info1 != null) { details.AddRange(info1.Details); } if (info2 != null) { details.AddRange(info2.Details); } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, details); info.SetDetailsName(this.Name); return true == isVerifySortEntitiesOrderByAsc && true == isVerifySortEntitiesOrderByDesc; }
/// <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; HttpStatusCode? statusCode1 = VerificationHelper.VerifySortEntities(context, SortedType.ASC, out passed, out info); if (info != null) { info.SetDetailsName(this.Name); } if (true != passed) { return passed; } HttpStatusCode? statusCode2 = VerificationHelper.VerifySortEntities(context, SortedType.DESC, out passed, out info); if (info != null) { info.SetDetailsName(this.Name); } 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; Uri metadataServiceUrl = new Uri(context.Destination.AbsoluteUri.TrimEnd('/') + @"/$metadata" + @"/"); var req = WebRequest.Create(metadataServiceUrl) as HttpWebRequest; Response response = WebHelper.Get(req, RuleEngineSetting.Instance().DefaultMaximumPayloadSize); ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name, metadataServiceUrl.AbsoluteUri, "GET", string.Empty, response); if (response != null && response.StatusCode == HttpStatusCode.OK && response.ResponsePayload.IsMetadata()) { passed = true; } else { passed = false; detail.ErrorMessage = "The response is not the metadata service document. Please refer to section 15 of [OData-CSDL]."; } 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; var response = WebHelper.Get(context.Destination, string.Empty, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name, context.Destination.AbsoluteUri, "GET", StringHelper.MergeHeaders(string.Empty, context.RequestHeaders), response); if (response != null && response.StatusCode != null) { if (context.PayloadFormat == RuleEngine.PayloadFormat.JsonLight) { passed = true; } else { passed = false; detail.ErrorMessage = "Get above URI with accept header 'application/json', the response is not JSON format."; } } else { passed = false; detail.ErrorMessage = String.Format("No response returned from above URI with accept header 'application/json'."); } 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.GetChangeTracking(context.MetadataDocument, context.VocCapabilities); if (string.IsNullOrEmpty(restrictions.Item1) || null == restrictions.Item2 || !restrictions.Item2.Any() || null == restrictions.Item3 || !restrictions.Item3.Any()) { detail.ErrorMessage = "Cannot find an entity-container or any entity-sets which support the change tracking function."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return passed; } string url = string.Format("{0}/{1}", context.ServiceBaseUri, restrictions.Item1); List<KeyValuePair<string, string>> requestHeaders = new List<KeyValuePair<string,string>>(); foreach (KeyValuePair<string, string> kvp in context.RequestHeaders) { requestHeaders.Add(new KeyValuePair<string, string>(kvp.Key, kvp.Value)); } // Add odata.track-changes preference in request header. KeyValuePair<string, string> prefer = new KeyValuePair<string, string>("Prefer", "odata.track-changes"); requestHeaders.Add(prefer); Response response = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, requestHeaders); detail = new ExtensionRuleResultDetail(this.Name, url, "GET", StringHelper.MergeHeaders(Constants.V4AcceptHeaderJsonFullMetadata, requestHeaders), response); if (response != null && !string.IsNullOrEmpty(response.ResponseHeaders)) { string preferHeader = response.ResponseHeaders.GetHeaderValue("Preference-Applied"); if (string.IsNullOrEmpty(preferHeader)) { passed = false; detail.ErrorMessage = "The response header returned by the service does not contain 'odata.track-changes', when request with the header 'Prefer:odata.track-changes'."; } else if (preferHeader.Contains("odata.track-changes")) { passed = true; } } else { passed = false; detail.ErrorMessage = "The service does not support Delta change tracking."; } 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; string selectedName = string.Empty; string functionactionName = "forFunctionAction"; // Use the XPath query language to access the metadata document and get all Namespace and Alias value. XElement metadata = XElement.Parse(context.MetadataDocument); string xpath = @"//*[local-name()='DataServices']/*[local-name()='Schema']"; List<string> appropriateNamespace = MetadataHelper.GetPropertyValues(context, xpath, "Namespace"); // Use the XPath query language to access the metadata document and get all Function names and all Action names. xpath = @"//*[local-name()='EntityContainer']/*[local-name()='FunctionImport']"; List<string> functionImportNames = MetadataHelper.GetPropertyValues(context, xpath, "Name"); xpath = @"//*[local-name()='EntityContainer']/*[local-name()='ActionImport']"; List<string> actionImportNames = MetadataHelper.GetPropertyValues(context, xpath, "Name"); if (!functionImportNames.Contains(functionactionName) && !actionImportNames.Contains(functionactionName)) { selectedName = functionactionName; } else { selectedName = functionactionName + "New"; } string url = string.Format("{0}/?$select={1}.{2}", context.Destination, appropriateNamespace[0], selectedName); var req = WebRequest.Create(url) as HttpWebRequest; var response = WebHelper.Get(req, RuleEngineSetting.Instance().DefaultMaximumPayloadSize); ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name, url, "GET", string.Empty, response); if (response != null && response.StatusCode != null) { if (response.StatusCode != HttpStatusCode.OK) { passed = true; } else { passed = false; detail.ErrorMessage = "The OData service MUST fail any request that contains actions or functions that it does not understand."; } } else { passed = false; detail.ErrorMessage = String.Format("No response returned 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) { bool? passed = null; info = null; HttpStatusCode? statusCode = VerificationHelper.VerifyCount(context, out passed, out info); if (info != null) { info.SetDetailsName(this.Name); } 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; 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); detail.ErrorMessage = @"This negative rule is not verified."; 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; var response = WebHelper.Get(context.Destination, Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name, context.Destination.AbsoluteUri, "GET", StringHelper.MergeHeaders(Constants.AcceptHeaderJson, context.RequestHeaders), response); if (response != null && response.StatusCode != null) { // Extracts OData-Version value from ResponseHttpHeaders. string oDataVersion = context.ResponseHttpHeaders.GetHeaderValue(Constants.ODataVersion).TrimEnd(';'); if (!string.IsNullOrEmpty(oDataVersion)) { float version = float.Parse(oDataVersion); // The minimal OData version of conformance validation is 4.0. if (version >= 4.0) { passed = true; } else { passed = false; detail.ErrorMessage = string.Format(@"The OData version is {0} which should be not less than minimal version 4.0.", version); } } else { passed = false; detail.ErrorMessage = @"Can not get the OData-Version header from response headers."; } } 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; info = null; VerificationHelper.VerifySearch(context, out passed, out info); if (info != null) { info.SetDetailsName(this.Name); } 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; string url = context.Destination.AbsoluteUri.TrimEnd('/') + @"/$metadata"; var response = WebHelper.Get(new Uri(url), string.Empty, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name, url, "GET", StringHelper.MergeHeaders(string.Empty, context.RequestHeaders), response); if (response != null && response.StatusCode != null) { // Get EntityContainer from metadata payload. string xpath = @"//*[local-name()='EntityContainer']"; XElement metadata = XElement.Parse(response.ResponsePayload); IEnumerable<XElement> entityContainer = metadata.XPathSelectElements(xpath, ODataNamespaceManager.Instance); List<string> propNames = new List<string>(); foreach (var prop in entityContainer) { propNames.Add(prop.Attribute("Name").Value); } if (propNames.Count > 0) { passed = true; } else { passed = false; detail.ErrorMessage = "There is no EntityContainer in metadata document."; } } else { passed = false; detail.ErrorMessage = String.Format("No response returned 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 svcDocResult = false; bool metadataResult = false; bool errorResponseResult = false; bool feedAndEntryResult = false; ExtensionRuleViolationInfo infoForOne = null; List<ExtensionRuleResultDetail> details = new List<ExtensionRuleResultDetail>(); svcDocResult = VerificationHelper.VerifySvcDoc(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } metadataResult = VerificationHelper.VerifyMetadata(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } errorResponseResult = VerificationHelper.VerifyError(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } feedAndEntryResult = VerificationHelper.VerifyFeedAndEntry(context, out infoForOne); if (infoForOne != null) { details.AddRange(infoForOne.Details); } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, details); info.SetDetailsName(this.Name); return svcDocResult && metadataResult && feedAndEntryResult && errorResponseResult; }
/// <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; string url = string.Format("{0}/?$find=*", context.Destination); var req = WebRequest.Create(url) as HttpWebRequest; Response response = WebHelper.Get(req, RuleEngineSetting.Instance().DefaultMaximumPayloadSize); ExtensionRuleResultDetail detail1 = new ExtensionRuleResultDetail(this.Name, url, "GET", string.Empty, response); if (response != null && response.StatusCode != null) { if (response.StatusCode != HttpStatusCode.OK) { passed = true; } else { passed = false; detail1.ErrorMessage = "Services SHOULD fail the above URI because it contains query options 'find' which services does not understand."; } } else { passed = false; detail1.ErrorMessage = "No response returned from above URI."; } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1); 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); 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.None).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; } // To get test entity which is deleteable and insertable EntityTypeElement entityType = null; foreach (var entityEle in entityTypeElements) { var matchEntity = entityEle.EntitySetName.GetRestrictions(serviceStatus.MetadataDocument, termDocs.VocCapabilitiesDoc, new List<Func<string, string, string, List<NormalProperty>, List<NavigProperty>, bool>>() { AnnotationsHelper.GetInsertRestrictions, AnnotationsHelper.GetDeleteRestrictions }); if (!string.IsNullOrEmpty(matchEntity.Item1) && matchEntity.Item2 != null && matchEntity.Item2.Any() && matchEntity.Item3 != null && matchEntity.Item3.Any()) { entityType = entityEle; break; } } if (null == entityType) { detail1.ErrorMessage = "To verify this rule it expects an entity type with deleteable and insertable restrictions, but there is no entity type in metadata which is insertable and deleteable."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1); return passed; } string entitySetUrl = entityType.EntitySetName.MapEntitySetNameToEntitySetURL(); if (string.IsNullOrEmpty(entitySetUrl)) { detail1.ErrorMessage = string.Format("Cannot find the entity-set URL which is matched with {0}.", entityType.EntityTypeShortName); info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1); return passed; } string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl; var additionalInfos = new List<AdditionalInfo>(); var reqData = dFactory.ConstructInsertedEntityData(entityType.EntitySetName, entityType.EntityTypeShortName, null, out additionalInfos); string reqDataStr = reqData.ToString(); bool isMediaType = !string.IsNullOrEmpty(additionalInfos.Last().ODataMediaEtag); var resp = WebHelper.CreateEntity(url, reqData, isMediaType, ref additionalInfos); detail1 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); // If create successfully, the resource is updatable and deletable. if (resp.StatusCode.HasValue && resp.StatusCode == HttpStatusCode.Created) { // Get feed response. 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 && resp.StatusCode == HttpStatusCode.OK) { JObject jo; resp.ResponsePayload.TryToJObject(out jo); var entries = JsonParserHelper.GetEntries(jo); foreach (JObject entry in entries) { if (entry[Constants.V4OdataEditLink] == null) { passed = false; detail2.ErrorMessage = "Not all entities from above URI contain edit links."; break; } } if (passed == null) { passed = true; } } else { passed = false; detail2.ErrorMessage = "Get feed resource failed from above URI."; } // Restore the service. var resps = WebHelper.DeleteEntities(additionalInfos); } else { passed = null; detail1.ErrorMessage = "Created new entity failed, it is not an updatable resource and can not verify this rule."; } var details = new List<ExtensionRuleResultDetail>() { detail1, detail2 }.RemoveNullableDetails(); info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details); return passed; }
/// <summary> /// Verify Entry.Core.4634 /// </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; const string relAttribPrefixName = @"http://docs.oasis-open.org/odata/ns/related/"; string xpath = string.Format(@"//*[local-name()='EntityType' and @Name='{0}']/*[local-name()='NavigationProperty']", context.EntityTypeShortName); XElement metadata = XElement.Parse(context.MetadataDocument); var navigProps = metadata.XPathSelectElements(xpath, ODataNamespaceManager.Instance); List<string> relURLFullNames = new List<string>(); foreach (var np in navigProps) { relURLFullNames.Add(relAttribPrefixName + np.Attribute(@"Name").Value); } xpath = @"/atom:entry/atom:link[@type='application/atom+xml;type=entry' or @type='application/atom+xml;type=feed']"; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(context.ResponsePayload); XmlNodeList linkElements = xmlDoc.SelectNodes(xpath, ODataNamespaceManager.Instance); foreach (XmlNode le in linkElements) { if (relURLFullNames.Contains(le.Attributes["rel"].Value) && Uri.IsWellFormedUriString(le.Attributes["rel"].Value, UriKind.Absolute)) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); break; } } return passed; }
/// <summary> /// Verify Entry.Core.4668 /// </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; var StreamTypeResultList = MetadataHelper.GetAllStreamTypeFromEntry(context.MetadataDocument, context.EntityTypeShortName); if (StreamTypeResultList.Count == 0) { info = null; return null; } XElement xePayload = XElement.Parse(context.ResponsePayload); string streamEditref = @"http://docs.oasis-open.org/odata/ns/edit-media/"; string streamReadref = @"http://docs.oasis-open.org/odata/ns/mediaresource/"; string editlinkFormat = string.Format("./*[local-name()='link' and @rel='{0}{1}']", streamEditref, @"{0}"); string readlinkFormat = string.Format("./*[local-name()='link' and @rel='{0}{1}']", streamReadref, @"{0}"); bool hasLinkNode = false; foreach (var xe in StreamTypeResultList) { string property = xe.GetAttributeValue("Name"); var xereadlink = xePayload.XPathSelectElement(string.Format(editlinkFormat, property), ODataNamespaceManager.Instance); var xeeditlink = xePayload.XPathSelectElement(string.Format(readlinkFormat, property), ODataNamespaceManager.Instance); if (xereadlink != null || xeeditlink != null) { hasLinkNode = true; } if (xereadlink != null) { if (xereadlink.GetAttributeValue(@"href") == null) { passed = false; break; } } if (xeeditlink != null) { if (xeeditlink.GetAttributeValue(@"href") == null) { passed = false; break; } } } if (hasLinkNode && passed == null) { passed = true; } info = new ExtensionRuleViolationInfo(passed == true ? null : 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; ServiceStatus serviceStatus = ServiceStatus.GetInstance(); TermDocuments termDocs = TermDocuments.GetInstance(); DataFactory dFactory = DataFactory.Instance(); var detail1 = new ExtensionRuleResultDetail(this.Name, serviceStatus.RootURL, HttpMethod.Post, string.Empty); var detail2 = 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.None).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; } // To get test entity which is of media type EntityTypeElement entityType = null; foreach (var entityEle in entityTypeElements) { if (MetadataHelper.IsMediaEntity(serviceStatus.MetadataDocument, entityEle.EntityTypeShortName, context)) { entityType = entityEle; break; } } if (null == entityType) { detail1.ErrorMessage = "To verify this rule it expects an entity type with deleteable and insertable restrictions, but there is no entity type in metadata which is insertable and deleteable."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1); return passed; } // Map 'entity-set name' to 'entity-set URL'. string entitySetUrl = entityType.EntitySetName.MapEntitySetNameToEntitySetURL(); if (string.IsNullOrEmpty(entitySetUrl)) { detail1.ErrorMessage = string.Format("Cannot find the entity-set URL which is matched with {0}", entityType.EntityTypeShortName); info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1); return passed; } string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl; var additionalInfos = new List<AdditionalInfo>(); var reqData = dFactory.ConstructInsertedEntityData(entityType.EntitySetName, entityType.EntityTypeShortName, null, out additionalInfos); string reqDataStr = reqData.ToString(); var resp = WebHelper.CreateEntity(url, context.RequestHeaders, reqData, true, ref additionalInfos); detail1 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); if (resp.StatusCode.HasValue && (HttpStatusCode.Created == resp.StatusCode || HttpStatusCode.NoContent == resp.StatusCode)) { string entityId = additionalInfos.Last().EntityId; resp = WebHelper.GetEntity(entityId); detail2 = new ExtensionRuleResultDetail(this.Name, entityId, HttpMethod.Get, string.Empty, resp); if (resp.StatusCode.HasValue && HttpStatusCode.OK == resp.StatusCode) { passed = true; } else { passed = false; detail2.ErrorMessage = "Can not get created entity 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 }.RemoveNullableDetails(); info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details); return passed; }
/// <summary> /// Verify Metadata.Core.4446 /// </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 labeledElementNodeList = xmlDoc.SelectNodes("//*[local-name()='LabeledElement']"); XmlNodeList labeledElementAttributeNodeList = xmlDoc.SelectNodes("//@LabeledElement"); if (labeledElementNodeList.Count > 0) { if (labeledElementAttributeNodeList.Count == 0) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); } } return passed; }
/// <summary> /// Verify Entry.Core.4617 /// </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 qualifiedName = "Edm."; List<string> xmlNodeTypes = new List<string>(); XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(context.ResponsePayload); XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable); nsmgr.AddNamespace("m", Constants.V3NSMetadata); string MeataNS = Constants.V3NSMetadata; string DataNs = Constants.V3NSData; if (context.Version == ODataVersion.V4) { nsmgr.AddNamespace("m", Constants.NSMetadata); MeataNS = Constants.NSMetadata; DataNs = Constants.V4NSData; } XmlNodeList xmlNodeList = xmlDoc.SelectNodes(@"//m:properties/*", nsmgr); foreach (XmlNode xmlNode in xmlNodeList) { if (xmlNode.NamespaceURI.Equals(DataNs) && xmlNode.Attributes["type", MeataNS] != null) { string xmlNodeName = xmlNode.LocalName; if (AtomSchemaHelper.IsBuiltInPrimitiveTypes(xmlNodeName, context, out xmlNodeTypes)) { foreach (string xmlNodeType in xmlNodeTypes) { string unqualifiedName = xmlNodeType.Remove(0, qualifiedName.Length); string metadataTypeValue = xmlNode.Attributes["type", MeataNS].Value; if (metadataTypeValue.Equals(unqualifiedName)) { passed = true; } else { passed = false; info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); break; } } if (passed == false) { break; } } } } 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 entityTypeShortName; var props = MetadataHelper.GetProperties("Edm.GeographyPoint", 1, out entityTypeShortName); if (null == props || !props.Any()) { return passed; } string propName = props[0].PropertyName; string srid = props[0].SRID; var entitySetUrl = entityTypeShortName.GetAccessEntitySetURL(); if (string.IsNullOrEmpty(entitySetUrl)) { 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) { JObject jObj = JObject.Parse(resp.ResponsePayload); JArray jArr = jObj.GetValue(Constants.Value) as JArray; var entity = jArr.First as JObject; var propVal = entity[propName]["coordinates"] as JArray; var pt1 = new Point(Convert.ToDouble(propVal[0]), Convert.ToDouble(propVal[1])); var pt2 = new Point(0.0, 0.0); var distance = Point.GetDistance(pt1, pt2); url = string.Format("{0}?$filter=geo.distance({1}, geography'POINT(0.0 0.0)') ge {2}", url, propName, distance); resp = WebHelper.Get(new Uri(url), string.Empty, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, svcStatus.DefaultHeaders); var detail = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, string.Empty); info = new ExtensionRuleViolationInfo(new Uri(url), string.Empty, detail); if (null != resp && HttpStatusCode.OK == resp.StatusCode) { jObj = JObject.Parse(resp.ResponsePayload); jArr = jObj.GetValue(Constants.Value) as JArray; foreach (JObject et in jArr) { propVal = et[propName]["coordinates"] as JArray; pt1 = new Point(Convert.ToDouble(propVal[0]), Convert.ToDouble(propVal[1])); pt2 = new Point(0.0, 0.0); var dis = Point.GetDistance(pt1, pt2); passed = dis >= distance; } } else { passed = false; } } 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.GetFilterRestrictions(context.MetadataDocument, context.VocCapabilities, supportedPropertyTypes,NavigationRoughType.None); if (string.IsNullOrEmpty(filterRestrictions.Item1) || null == filterRestrictions.Item2 || !filterRestrictions.Item2.Any()) { detail.ErrorMessage = "Cannot find an appropriate entity-set which supports Less 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=(1 add 0) mul {2} sub {3} lt 2"; 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 '()'."; 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 '()'."; return passed; } var entities2 = JsonParserHelper.GetEntries(feed2).ToList(); var temp = entities2.FindAll(en => en.Value<Int64>(primitivePropName) - propVal < 2).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 '()'."; } 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); 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, navigPropName); 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> /// Verify Common.Core.4038 /// </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 OdataNextLink = Constants.V4OdataNextLink; if (context.Version == ODataVersion.V3) { OdataNextLink = Constants.OdataNextLink; } string OdataDeltaLink = Constants.V4OdataDeltaLink; if (context.Version == ODataVersion.V3) { OdataDeltaLink = Constants.V4OdataDeltaLink; } // Verify whether odata.nextLink annotation in response. bool isnextLinkExist = JsonParserHelper.IsSpecifiedAnnotationExist(context, OdataNextLink); // Verify whether odata.deltaLink annotation in response. bool isdeltaLinkExist = JsonParserHelper.IsSpecifiedAnnotationExist(context, OdataDeltaLink); // Response must not have both an odata.deltaLink annotation and an odata.nextLink annotation. if (isnextLinkExist && isdeltaLinkExist) { passed = false; } else { passed = true; } return passed; }
/// <summary> /// Verify Metadata.Core.4120 /// </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; var metadata = XElement.Parse(context.MetadataDocument); string xPath = "//*[local-name()='NavigationProperty']"; var navigationPropertyElems = metadata.XPathSelectElements(xPath, ODataNamespaceManager.Instance) .Where(np => null != np.Attribute("Partner") && null != np.Attribute("Type") && null != np.Attribute("Name")) .Select(np => np); if (null != navigationPropertyElems && navigationPropertyElems.Any()) { foreach (var navigationPropertyElem in navigationPropertyElems) { string navigationPropertyName = navigationPropertyElem.GetAttributeValue("Name"); string typeShortName1 = navigationPropertyElem.GetAttributeValue("Type").RemoveCollectionFlag().GetLastSegment(); string partnerNavigationPropertyName1 = navigationPropertyElem.GetAttributeValue("Partner"); xPath = string.Format("//*[(local-name()='EntityType' or local-name()='ComplexType') and @Name='{0}']/*[local-name()='NavigationProperty' and @Name='{1}']", typeShortName1, partnerNavigationPropertyName1); var npElem = metadata.XPathSelectElement(xPath, ODataNamespaceManager.Instance); if (null != npElem.Parent) { var parentElem = npElem.Parent; var derivedList = parentElem.GetAttributeValue("Name").GetEntityTypeShortNamesFromDerivedType(); if (!derivedList.Any() && "ComplexType" != parentElem.Name.LocalName) { string partnerNavigationPropertyName2 = null != npElem.Attribute("Partner") ? npElem.GetAttributeValue("Partner") : string.Empty; if (partnerNavigationPropertyName2 == navigationPropertyName) { passed = true; } else { passed = false; break; } } } } } info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); 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; JObject entry; context.ResponsePayload.TryToJObject(out entry); var o = (JObject)entry; var jProps = o.Children(); string odataIdName = Constants.V4OdataId; if (context.Version == ODataVersion.V3) { odataIdName = Constants.OdataId; } foreach (JProperty jProp in jProps) { // Whether odata.id exist in minimal metadata cases. if (jProp.Name.Contains(odataIdName)) { // If odata.id exist in minimal metadata, the value of odata.id must deviate from the canonical URL of the entity. if (!jProp.Value.ToString().StripOffDoubleQuotes().Equals(context.DestinationBasePath)) { passed = true; break; } 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); var detail4 = new ExtensionRuleResultDetail(this.Name); var detail5 = new ExtensionRuleResultDetail(this.Name); var detail6 = new ExtensionRuleResultDetail(this.Name); var entityType = MetadataHelper.GetConcurrencyEntityType(serviceStatus.MetadataDocument); if (null == entityType) { detail1.ErrorMessage = "Cannot find an entity which contains a concurrency property in the service."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1); return passed; } var normalPropNames = entityType.NormalProperties.Where(np => "Edm.String" == np.PropertyType && !np.IsKey).Select(np => np.PropertyName); if (normalPropNames.Any()) { string entitySetUrl = entityType.EntitySetName.MapEntitySetNameToEntitySetURL(); string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl; var additionalInfos = new List<AdditionalInfo>(); var reqData = dFactory.ConstructInsertedEntityData(entityType.EntitySetName, entityType.EntityTypeShortName, null, out additionalInfos); string reqDataStr = reqData.ToString(); bool isMediaType = !string.IsNullOrEmpty(additionalInfos.Last().ODataMediaEtag); var resp = WebHelper.CreateEntity(url, reqData, isMediaType, ref additionalInfos); detail1 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.Created == resp.StatusCode) { var entityId = additionalInfos.Last().EntityId; var hasEtag = additionalInfos.Last().HasEtag; if (!hasEtag) { detail1.ErrorMessage = "The new inserted entity does not contain an @odata.etag annotation."; info = new ExtensionRuleViolationInfo(new Uri(entityId), resp.ResponsePayload, detail2); return passed; } resp = WebHelper.GetEntity(entityId, serviceStatus.DefaultHeaders); detail2 = new ExtensionRuleResultDetail(this.Name, entityId, HttpMethod.Get, StringHelper.MergeHeaders(string.Empty, serviceStatus.DefaultHeaders), resp); if (HttpStatusCode.OK == resp.StatusCode) { reqDataStr = dFactory.ConstructUpdatedEntityData(reqData, normalPropNames).ToString(); var header = new KeyValuePair<string, string>("If-Match", additionalInfos.Last().ODataEtag); var headers = new List<KeyValuePair<string, string>>() { header }; resp = WebHelper.UpdateEntity(entityId, reqDataStr, HttpMethod.Patch, headers); detail3 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Patch, StringHelper.MergeHeaders(string.Empty, headers), resp, string.Empty, reqDataStr); if (HttpStatusCode.NoContent == resp.StatusCode) { resp = WebHelper.GetEntity(entityId, serviceStatus.DefaultHeaders); detail4 = new ExtensionRuleResultDetail(this.Name, entityId, HttpMethod.Get, StringHelper.MergeHeaders(string.Empty, serviceStatus.DefaultHeaders), resp); if (HttpStatusCode.OK == resp.StatusCode) { resp = WebHelper.DeleteEntity(entityId, hasEtag); detail5 = new ExtensionRuleResultDetail(this.Name, entityId, HttpMethod.Delete, StringHelper.MergeHeaders(string.Empty, new List<KeyValuePair<string, string>>() { header }), resp); if (HttpStatusCode.NoContent == resp.StatusCode) { resp = WebHelper.GetEntity(entityId); detail6 = new ExtensionRuleResultDetail(this.Name, entityId, HttpMethod.Get, string.Empty, resp); if (HttpStatusCode.NotFound == resp.StatusCode) { passed = true; } else { passed = false; detail6.ErrorMessage = "It still can get the deleted entity from above URI."; } } else { passed = false; detail5.ErrorMessage = "Delete entity failed."; } } else { passed = false; detail4.ErrorMessage = "Can not get the created entity from above URI."; } } else { passed = false; detail3.ErrorMessage = "Update entity failed."; } } } else { passed = false; detail1.ErrorMessage = "Created the new entity failed for above URI."; } } var details = new List<ExtensionRuleResultDetail>() { detail1, detail2, detail3, detail4, detail5, detail6 }.RemoveNullableDetails(); info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details); return passed; }
/// <summary> /// Verify Metadata.Core.4265 /// </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; var metadata = XElement.Parse(context.MetadataDocument); string xPath = "//*[local-name()='Function']"; var functionElems = metadata.XPathSelectElements(xPath, ODataNamespaceManager.Instance); if (null != functionElems && functionElems.Any()) { foreach (var functionElem in functionElems) { if (null != functionElem.Attribute("Name")) { string nameAttribVal = functionElem.GetAttributeValue("Name"); if (nameAttribVal.IsSimpleIdentifier()) { passed = true; } else { passed = false; break; } } else { passed = false; break; } } } info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload); return passed; }
public ServiceVerificationResult(bool?passed, ExtensionRuleViolationInfo violationInfo, HttpStatusCode?responseStatusCode = null) { Passed = passed; ViolationInfo = violationInfo; ResponseStatusCode = responseStatusCode; }