/// <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; }
public ExtensionRuleViolationInfo(Uri uri, string content, ExtensionRuleResultDetail detail) { this.Endpoint = uri; this.Content = content; this.Details = new List <ExtensionRuleResultDetail>(); if (detail != null) { this.Details.Add(detail.Clone()); } }
public ExtensionRuleViolationInfo(Uri uri, string content, ExtensionRuleResultDetail detail) { this.Endpoint = uri; this.Content = content; this.Details = new List<ExtensionRuleResultDetail>(); if (detail != null) { this.Details.Add(detail.Clone()); } }
/// <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; }
public ExtensionRuleResultDetail Clone() { ExtensionRuleResultDetail desDetail = new ExtensionRuleResultDetail(); desDetail.RuleName = this.RuleName; desDetail.URI = this.URI; desDetail.HTTPMethod = this.HTTPMethod; desDetail.RequestHeaders = this.RequestHeaders; desDetail.RequestData = this.RequestData; desDetail.ResponseStatusCode = this.ResponseStatusCode; desDetail.ResponseHeaders = this.ResponseHeaders; desDetail.ResponsePayload = this.ResponsePayload; desDetail.ErrorMessage = this.ErrorMessage; return(desDetail); }
/// <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; string url = context.Destination.AbsoluteUri + @"/$metadata"; Response 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); // Get EntityContainer from metadata response 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 metadat document."; } 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 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); 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> /// 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 propTypes = new string[2] { "Edm.Date", "Edm.DateTimeOffset" }; var propNames = MetadataHelper.GetPropertyNames(propTypes, out entityTypeShortName); if (null == propNames || !propNames.Any()) { return passed; } string propName = propNames[0]; 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) { var settings = new JsonSerializerSettings(); settings.DateParseHandling = DateParseHandling.None; JObject jObj = JsonConvert.DeserializeObject(resp.ResponsePayload, settings) as JObject; JArray jArr = jObj.GetValue(Constants.Value) as JArray; var entity = jArr.First as JObject; var propVal = entity[propName].ToString(); int index = propVal.IndexOf('T'); propVal = propVal.Substring(index + 1, 2); url = string.Format("{0}?$filter=hour({1}) eq {2}", url, propName, propVal); 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 = JsonConvert.DeserializeObject(resp.ResponsePayload, settings) as JObject; jArr = jObj.GetValue(Constants.Value) as JArray; if (null == jArr || !jArr.Any()) { return false; } foreach (JObject et in jArr) { passed = et[propName].ToString().Substring(index + 1, 2) == propVal; } } else { passed = false; } } return passed; }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name); var entitySets = MetadataHelper.GetFeeds(context.MetadataDocument); if (null == entitySets || !entitySets.Any()) { detail.ErrorMessage = "Cannot find any entity-sets in metadata document."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return passed; } string entitySet = string.Empty; foreach (var set in entitySets) { if (true == set.IsSupportAsynchronousOperation(context.MetadataDocument, new List<string>() { context.VocCapabilities })) { entitySet = set; break; } } if (string.IsNullOrEmpty(entitySet)) { detail.ErrorMessage = "Cannot find an appropriate entity-set which supports asynchronous operation in metadata document."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); return passed; } string url = string.Format("{0}/{1}", context.ServiceBaseUri, entitySet); 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 respond-async preference in request header. KeyValuePair<string, string> prefer = new KeyValuePair<string, string>("Prefer", "respond-async"); 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 ) { if(response.StatusCode == HttpStatusCode.Accepted) { passed = true; } else if (!string.IsNullOrEmpty(response.ResponseHeaders)) { string preferHeader = response.ResponseHeaders.GetHeaderValue("Preference-Applied"); if (!string.IsNullOrEmpty(preferHeader) && preferHeader.Contains("respond-async")) { passed = true; } else { passed = false; detail.ErrorMessage = "The service does not support Asynchronous operations."; } } } else { detail.ErrorMessage = "The service does not support Asynchronous operations."; } 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; ServiceStatus serviceStatus = ServiceStatus.GetInstance(); TermDocuments termDocs = TermDocuments.GetInstance(); DataFactory dFactory = DataFactory.Instance(); var detail1 = new ExtensionRuleResultDetail(this.Name); var detail2 = new ExtensionRuleResultDetail(this.Name); var detail3 = new ExtensionRuleResultDetail(this.Name); List<string> keyPropertyTypes = new List<string>() { "Edm.Int32", "Edm.Int16", "Edm.Int64", "Edm.Guid", "Edm.String" }; List<EntityTypeElement> entityTypeElements = MetadataHelper.GetEntityTypes(serviceStatus.MetadataDocument, 1, keyPropertyTypes, null, NavigationRoughType.SingleValued).ToList(); if (null == entityTypeElements || 0 == entityTypeElements.Count()) { detail1.ErrorMessage = "To verify this rule it expects an entity type with Int32/Int64/Int16/Guid/String key property, but there is no this entity type in metadata so can not verify this rule."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1); return passed; } string entityTypeShortName = string.Empty; string entitySetName = string.Empty; string entitySetUrl = string.Empty; string navigPropName = string.Empty; foreach (var en in entityTypeElements) { var matchEntity = en.EntitySetName.GetRestrictions(serviceStatus.MetadataDocument, termDocs.VocCapabilitiesDoc, new List<Func<string, string, string, List<NormalProperty>, List<NavigProperty>, bool>>() { AnnotationsHelper.GetExpandRestrictions, AnnotationsHelper.GetInsertRestrictions , AnnotationsHelper.GetDeleteRestrictions, AnnotationsHelper.GetUpdateRestrictions }); if (!string.IsNullOrEmpty(matchEntity.Item1) && matchEntity.Item2 != null && matchEntity.Item2.Any() && matchEntity.Item3 != null && matchEntity.Item3.Any()) { entityTypeShortName = en.EntityTypeShortName; entitySetName = matchEntity.Item1; entitySetUrl = entitySetName.MapEntitySetNameToEntitySetURL(); foreach (NavigProperty np in matchEntity.Item3) { string nEntityTypeShortName = np.NavigationPropertyType.RemoveCollectionFlag().GetLastSegment(); if (np.NavigationRoughType == NavigationRoughType.SingleValued && !nEntityTypeShortName.IsMediaType()) { navigPropName = np.NavigationPropertyName; break; } } } if (!string.IsNullOrEmpty(entitySetName) && !string.IsNullOrEmpty(navigPropName)) { break; } } if (string.IsNullOrEmpty(entitySetName) || string.IsNullOrEmpty(navigPropName)) { detail1.ErrorMessage = "Cannot find the appropriate entity-set URL to verify this rule."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1); return passed; } string navigPropEntitySet = navigPropName.MapNavigationPropertyNameToEntitySetURL(entityTypeShortName); string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl; var additionalInfos = new List<AdditionalInfo>(); var reqData = dFactory.ConstructInsertedEntityData(entitySetName, entityTypeShortName, new List<string>() { navigPropName }, out additionalInfos); string reqDataStr = reqData.ToString(); bool isMediaType = !string.IsNullOrEmpty(additionalInfos.Last().ODataMediaEtag); var resp = WebHelper.CreateEntity(url, reqData, isMediaType, ref additionalInfos); detail1 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.Created == resp.StatusCode) { string entityId = additionalInfos.Last().EntityId; url = serviceStatus.RootURL.TrimEnd('/') + @"/" + navigPropEntitySet; resp = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, serviceStatus.DefaultHeaders); detail2 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, StringHelper.MergeHeaders(Constants.V4AcceptHeaderJsonFullMetadata, serviceStatus.DefaultHeaders), resp); if (resp.StatusCode.HasValue && HttpStatusCode.OK == resp.StatusCode) { JObject feed; resp.ResponsePayload.TryToJObject(out feed); var entities = JsonParserHelper.GetEntries(feed); if (entities.Any()) { string v4OdataIdVal = string.Empty; if (entities.First[Constants.V4OdataId] != null) { v4OdataIdVal = entities.First[Constants.V4OdataId].ToString(); } url = string.Format("{0}/{1}/$ref", entityId, navigPropName); reqDataStr = @"{ """ + Constants.V4OdataId + @""" : """ + v4OdataIdVal + @""" }"; bool hasEtag = additionalInfos.Last().HasEtag; resp = WebHelper.UpdateEntity(url, reqDataStr, HttpMethod.Put, hasEtag); detail3 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Put, string.Empty, resp, string.Empty, reqDataStr); if (null != resp && HttpStatusCode.NoContent == resp.StatusCode) { passed = true; } else { passed = false; detail3.ErrorMessage = "PUT to $ref failed by above URI"; } } } else { passed = false; detail2.ErrorMessage = "Get entity failed from above URI."; } // Restore the service. var resps = WebHelper.DeleteEntities(additionalInfos); } else { passed = false; detail1.ErrorMessage = "Created the new entity failed for above URI."; } var details = new List<ExtensionRuleResultDetail>() { detail1, detail2, detail3 }.RemoveNullableDetails(); info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details); return passed; }
/// <summary> /// Verifies the 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 navigPropNames = MetadataHelper.GetNavigationPropertyNames(out entityTypeShortName); if (null == navigPropNames || !navigPropNames.Any()) { return passed; } string navigPropName = navigPropNames[0]; navigPropNames.RemoveAt(0); var entitySetUrl = entityTypeShortName.MapEntityTypeShortNameToEntitySetURL(); string url = string.Format("{0}/{1}?$expand={2}", svcStatus.RootURL.TrimEnd('/'), entitySetUrl, navigPropName); var resp = WebHelper.Get(new Uri(url), string.Empty, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, svcStatus.DefaultHeaders); var detail = new ExtensionRuleResultDetail("ServiceImpl_SystemQueryOptionExpand", url, HttpMethod.Get, string.Empty); info = new ExtensionRuleViolationInfo(new Uri(url), string.Empty, detail); if (null != resp && HttpStatusCode.OK == resp.StatusCode) { var jObj = JObject.Parse(resp.ResponsePayload); var jArr = jObj.GetValue("value") as JArray; foreach (JObject entity in jArr) { passed = false; foreach (JProperty prop in entity.Children()) { if (prop.Name == navigPropName) { passed = true; break; } } } } return passed; }
/// <summary> /// Add detail information to extension info. /// </summary> /// <param name="detail"></param> public void AddDetail(ExtensionRuleResultDetail detail) { this.Details.Add(detail); }
/// <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> /// 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 detail = new ExtensionRuleResultDetail(this.Name, serviceStatus.RootURL, HttpMethod.Post, string.Empty); List<string> keyPropertyTypes = new List<string>() { "Edm.Int32", "Edm.Int16", "Edm.Int64", "Edm.Guid", "Edm.String" }; List<EntityTypeElement> entityTypeElements = MetadataHelper.GetEntityTypes(serviceStatus.MetadataDocument, 1, keyPropertyTypes, null, NavigationRoughType.None).ToList(); if (null == entityTypeElements || 0 == entityTypeElements.Count()) { detail.ErrorMessage = "To verify this rule it expects an entity type with Int32/Int64/Int16/Guid/String key property, but there is no this entity type in metadata so can not verify this rule."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail); return passed; } EntityTypeElement eTypeElement = new EntityTypeElement(); foreach (var en in entityTypeElements) { if (MetadataHelper.IsMediaEntity(serviceStatus.MetadataDocument, en.EntityTypeShortName, context) && !string.IsNullOrEmpty(en.EntitySetName)) { eTypeElement = en; break; } } if (eTypeElement.EntityTypeShortName == null) { detail.ErrorMessage = "Cannot find the appropriate media entity type to verify this rule."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail); return passed; } string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + eTypeElement.EntitySetName; var additionalInfos = new List<AdditionalInfo>(); var reqData = dFactory.ConstructInsertedEntityData(eTypeElement.EntitySetName, eTypeElement.EntityTypeShortName, null, out additionalInfos); string reqDataStr = reqData.ToString(); var resp = WebHelper.CreateEntity(url, context.RequestHeaders, reqData, true, ref additionalInfos); detail = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.Created == resp.StatusCode || HttpStatusCode.NoContent == resp.StatusCode) { url = additionalInfos.Last().EntityId.TrimEnd('/') + "/$value"; if(url.Equals("/$value")) { detail.ErrorMessage = string.Format("Fail to find the image read and edit URL.", resp.StatusCode); return passed; } resp = WebHelper.Get(new Uri(url), null, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, null); detail = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, StringHelper.MergeHeaders(Constants.V4AcceptHeaderJsonFullMetadata, serviceStatus.DefaultHeaders), resp); if (resp.StatusCode.HasValue && HttpStatusCode.OK == resp.StatusCode) { resp = WebHelper.UpdateMediaTypeEntity(url, context.RequestHeaders, additionalInfos.Last().HasEtag); detail = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Put, string.Empty, resp, string.Empty, "Successfully updated the stream of the image."); if (null != resp && (HttpStatusCode.NoContent == resp.StatusCode || resp.StatusCode == HttpStatusCode.OK)) { passed = true; } else { passed = false; detail.ErrorMessage = string.Format("HTTP PUT to update the image failed with the error {0}.", resp.StatusCode); } } else { detail.ErrorMessage = "Get entity image failed from above URI."; } // Restore the service. var resps = WebHelper.DeleteEntities(context.RequestHeaders, additionalInfos); } else { detail.ErrorMessage = "Created the new entity failed for above URI."; } var details = new List<ExtensionRuleResultDetail>() { detail }; info = new ExtensionRuleViolationInfo(new Uri(url), serviceStatus.ServiceDocument, details); return passed; }
/// <summary> /// Verifies the 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 propTypes = new string[1] { "Edm.DateTimeOffset" }; var propNames = MetadataHelper.GetPropertyNames(propTypes, out entityTypeShortName); if (null == propNames || !propNames.Any()) { return passed; } string propName = propNames[0]; 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 = Convert.ToDateTime(entity[propName]).TimeOfDay.ToString(); url = string.Format("{0}?$filter=time({1}) eq time('{1}')", url, propName); 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) { passed = Convert.ToDateTime(et[propName]).TimeOfDay.ToString() == propVal; } } else { passed = false; } } return passed; }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; info = null; 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> /// 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.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) { 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; } string navigPropName = null; string navigPropRelatedEntityTypeShortName = null; string navigPropRelatedEntitySetName = null; string navigPropRelatedEntitySetUrl = null; NormalProperty navigPropRelatedEntityTypeKey = null; foreach (var np in matchEntity.Item3) { navigPropName = np.NavigationPropertyName; navigPropRelatedEntityTypeShortName = np.NavigationPropertyType.RemoveCollectionFlag().GetLastSegment(); List<NormalProperty> navigKeyProps = MetadataHelper.GetKeyProperties(serviceStatus.MetadataDocument, navigPropRelatedEntityTypeShortName).ToList(); if (navigKeyProps.Count == 1 && keyPropertyTypes.Contains(navigKeyProps[0].PropertyType)) { navigPropRelatedEntitySetName = navigPropRelatedEntityTypeShortName.MapEntityTypeShortNameToEntitySetName(); navigPropRelatedEntitySetUrl = navigPropRelatedEntityTypeShortName.MapEntityTypeShortNameToEntitySetURL(); navigPropRelatedEntityTypeKey = navigKeyProps[0]; break; } } if (null != navigPropRelatedEntityTypeKey && !string.IsNullOrEmpty(navigPropRelatedEntitySetUrl)) { string entitySetUrl = et.EntitySetName.MapEntitySetNameToEntitySetURL(); string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl; var additionalInfos1 = new List<AdditionalInfo>(); var reqData = dFactory.ConstructInsertedEntityData(et.EntitySetName, et.EntityTypeShortName, null, out additionalInfos1); string reqDataStr = reqData.ToString(); bool isMediaType = !string.IsNullOrEmpty(additionalInfos1.Last().ODataMediaEtag); var resp = WebHelper.CreateEntity(url, reqData, isMediaType, ref additionalInfos1); detail1 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); if (resp.StatusCode.HasValue && HttpStatusCode.Created == resp.StatusCode) { string entityId = additionalInfos1.Last().EntityId; url = serviceStatus.RootURL.TrimEnd('/') + @"/" + navigPropRelatedEntitySetUrl; if (string.IsNullOrEmpty(navigPropRelatedEntityTypeShortName)) { continue; } var navigPropEntityType = navigPropRelatedEntityTypeShortName.GetSpecifiedEntityType(serviceStatus.MetadataDocument); if (null == navigPropEntityType) { continue; } url = string.Format("{0}/{1}", entityId, navigPropName); var additionalInfos2 = new List<AdditionalInfo>(); reqData = dFactory.ConstructInsertedEntityData(navigPropRelatedEntitySetName, navigPropRelatedEntityTypeShortName, null, out additionalInfos2); reqDataStr = reqData.ToString(); isMediaType = !string.IsNullOrEmpty(additionalInfos2.Last().ODataMediaEtag); resp = WebHelper.CreateEntity(url, reqData, isMediaType, ref additionalInfos2); detail2 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); if (resp.StatusCode.HasValue && resp.StatusCode == HttpStatusCode.Created) { passed = true; // Restore the service. var resps2 = WebHelper.DeleteEntities(additionalInfos2); } else { passed = false; detail2.ErrorMessage = "Create entity failed for above URI."; } // Restore the service. var resps1 = WebHelper.DeleteEntities(additionalInfos1); } else { passed = false; detail1.ErrorMessage = "Created the new entity failed for above URI."; } } if (false == passed) { break; } } var details = new List<ExtensionRuleResultDetail>() { detail1, detail2 }.RemoveNullableDetails(); info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details); return passed; }
/// <summary> /// Verifies the extension rule. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if rule passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; List<string> expectedTypes = new List<string>() { "Edm.String", "Edm.Int32", "Edm.Int16", "Edm.Single", "Edm.Double", "Edm.Boolean", "Edm.DateTimeOffset", "Edm.Guid" }; ExtensionRuleResultDetail detail1 = new ExtensionRuleResultDetail(this.Name); var restrictions = AnnotationsHelper.GetRestrictions( context.MetadataDocument, context.VocCapabilities, new List<Func<string, string, string, List<NormalProperty>, List<NavigProperty>, bool>>() { AnnotationsHelper.GetExpandRestrictions, AnnotationsHelper.GetFilterRestrictions }, null, NavigationRoughType.CollectionValued); if (string.IsNullOrEmpty(restrictions.Item1) || null == restrictions.Item2 || !restrictions.Item2.Any() || null == restrictions.Item3 || !restrictions.Item3.Any()) { detail1.ErrorMessage = "Cannot find an appropriate entity-set which supports $expand, $filter system query options in the service."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1); return passed; } string entitySet = restrictions.Item1; string navigPropName = string.Empty; string navigPropType = string.Empty; foreach (var np in restrictions.Item3) { if (NavigationRoughType.CollectionValued == np.NavigationRoughType) { navigPropName = np.NavigationPropertyName; navigPropType = np.NavigationPropertyType; } } string entityType = navigPropType.RemoveCollectionFlag().GetLastSegment(); var tmp = MetadataHelper.GetPropertiesWithSpecifiedTypeFromEntityType(entityType, context.MetadataDocument, expectedTypes); if (null == tmp && !tmp.Any()) { detail1.ErrorMessage = "Cannot find an appropriate primitive properties of entity type in the service."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1); return passed; } var str = tmp.First().Split(','); string primitivePropertyName = str[0]; string primitivePropertyType = str[1]; if (string.IsNullOrEmpty(entitySet)) { detail1.ErrorMessage = "Cannot find an appropriate entity-set which supports $expand system query option."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1); return passed; } if (string.IsNullOrEmpty(navigPropName) || string.IsNullOrEmpty(navigPropType)) { detail1.ErrorMessage = "Cannot get expanded entities because cannot get collection type of navigation property from metadata"; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1); return passed; } if (string.IsNullOrEmpty(primitivePropertyName) || string.IsNullOrEmpty(primitivePropertyType)) { detail1.ErrorMessage = "Cannot get an appropriate primitive property from navigation properties."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1); return passed; } Uri uri = new Uri(string.Format("{0}/{1}?$expand={2}", context.ServiceBaseUri, entitySet, navigPropName)); var response = WebHelper.Get(uri, Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); if (HttpStatusCode.OK != response.StatusCode) { passed = false; detail1.ErrorMessage = JsonParserHelper.GetErrorMessage(response.ResponsePayload); info = new ExtensionRuleViolationInfo(uri, response.ResponsePayload, detail1); return passed; } JObject feed; response.ResponsePayload.TryToJObject(out feed); if (feed != null && JTokenType.Object == feed.Type) { var entities = JsonParserHelper.GetEntries(feed); var navigProp = entities[0][navigPropName] as JArray; if (navigProp != null && navigProp.Count != 0) { string propVal = navigProp[0][primitivePropertyName].ToString(); string compareVal = propVal; if (primitivePropertyType.Equals("Edm.String")) { compareVal = "'" + propVal + "'"; } string url = string.Format("{0}/{1}?$expand={2}($filter={3} eq {4})", context.ServiceBaseUri, entitySet, navigPropName, primitivePropertyName, compareVal); var resp = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); detail1 = new ExtensionRuleResultDetail(this.Name, url, "GET", StringHelper.MergeHeaders(Constants.AcceptHeaderJson, context.RequestHeaders), resp); if (resp.StatusCode == HttpStatusCode.OK) { JObject jObj; resp.ResponsePayload.TryToJObject(out jObj); if (jObj != null && JTokenType.Object == jObj.Type) { var entries = JsonParserHelper.GetEntries(jObj).ToList(); foreach (var entry in entries) { if (entry[navigPropName] != null && ((JArray)entry[navigPropName]).Count == 0) { continue; } else if (entry[navigPropName] != null && ((JArray)entry[navigPropName]).Count > 0) { var temp = entry[navigPropName].ToList() .FindAll(en => propVal == en[primitivePropertyName].ToString()) .Select(en => en); if (entry[navigPropName].ToList().Count == temp.Count()) { passed = true; } else { passed = false; detail1.ErrorMessage = string.Format("The service does not execute an accurate result on system query option '$filter' (Actual Value: {0}, Expected Value: {1}).", entry[navigPropName].ToList().Count, temp.Count()); break; } } } } } else { passed = false; detail1.ErrorMessage = "The service does not support system query option '$filter' on expanded entities."; } } } 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(); DataFactory dFactory = DataFactory.Instance(); var detail = new ExtensionRuleResultDetail(this.Name, serviceStatus.RootURL, HttpMethod.Post, string.Empty); string updateUrl = serviceStatus.RootURL; List<string> keyPropertyTypes = new List<string>() { "Edm.Int32", "Edm.Int16", "Edm.Int64", "Edm.Guid", "Edm.String" }; List<string> norPropertyTypes = new List<string>() { "Edm.String" }; List<EntityTypeElement> entityTypeElements = MetadataHelper.GetEntityTypes(serviceStatus.MetadataDocument, 1, keyPropertyTypes, null, NavigationRoughType.None).ToList(); if (null == entityTypeElements || 0 == entityTypeElements.Count) { detail.ErrorMessage = "To verify this rule it expects an entity type with Int32/Int64/Int16/Guid/String key property and a string type normal property, but there is no this entity type in metadata so can not verify this rule."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail); return passed; } EntityTypeElement entityType = null; List<string> navigationPropNames = new List<string>(); foreach (var en in entityTypeElements) { if (MetadataHelper.HasEntityNavigationProp(serviceStatus.MetadataDocument, en.EntityTypeShortName, NavigationRoughType.CollectionValued, context, out navigationPropNames)) { entityType = en; break; } } if (navigationPropNames!=null && !navigationPropNames.Any()) { detail.ErrorMessage = "To verify this rule it is expected that an entity type has collection-valued navigation type property, but there is no such entity type in metadata so can not verify this rule."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail); return passed; } string navigationPropName = navigationPropNames.First(); string entitySetUrl = entityType.EntitySetName.MapEntitySetNameToEntitySetURL(); updateUrl = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl; if (string.IsNullOrEmpty(entitySetUrl)) { detail.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, detail); return passed; } string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl; var additionalInfosAll = new List<AdditionalInfo>(); var additionalInfos = new List<AdditionalInfo>(); var reqData = dFactory.ConstructInsertedEntityData(entityType.EntitySetName, entityType.EntityTypeShortName, null, out additionalInfos); additionalInfosAll = additionalInfos; string reqDataStr = reqData.ToString(); bool isMediaType = !string.IsNullOrEmpty(additionalInfos.Last().ODataMediaEtag); var resp = WebHelper.CreateEntity(url, context.RequestHeaders, reqData, isMediaType, ref additionalInfos); detail = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.Created == resp.StatusCode) { string entityId = additionalInfos.Last().EntityId; string nPropUrl = entityId.TrimEnd('/') + "/" + navigationPropName; updateUrl = entityId.TrimEnd('/') + "/" + navigationPropName + "/$ref"; bool hasEtag = additionalInfos.Last().HasEtag; resp = WebHelper.GetEntity(updateUrl); detail = new ExtensionRuleResultDetail(this.Name, updateUrl, HttpMethod.Get, string.Empty, resp); if (HttpStatusCode.OK == resp.StatusCode) { string navigPropType = MetadataHelper.GetNavigPropertyTypeFromMetadata(navigationPropName, entityType.EntityTypeShortName, serviceStatus.MetadataDocument); string navigPropTypeShortName = navigPropType.Substring(navigPropType.IndexOf("(")).GetLastSegment().TrimEnd(')'); string nEntitySetName = navigationPropName.MapNavigationPropertyNameToEntitySetName(entityType.EntityTypeShortName); string nEntitySetUrl = nEntitySetName.MapEntitySetNameToEntitySetURL(); nEntitySetUrl = serviceStatus.RootURL.TrimEnd('/') + @"/" + nEntitySetUrl; reqData = dFactory.ConstructInsertedEntityData(nEntitySetName, navigPropTypeShortName, null, out additionalInfos); foreach(AdditionalInfo a in additionalInfos) { additionalInfosAll.Add(a); } reqDataStr = reqData.ToString(); isMediaType = !string.IsNullOrEmpty(additionalInfos.Last().ODataMediaEtag); resp = WebHelper.CreateEntity(nEntitySetUrl, context.RequestHeaders, reqData, isMediaType, ref additionalInfos); detail = new ExtensionRuleResultDetail(this.Name, nEntitySetUrl, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.Created == resp.StatusCode) { string refEntityId = additionalInfos.Last().EntityId; resp = WebHelper.GetEntity(refEntityId); detail = new ExtensionRuleResultDetail(this.Name, refEntityId, HttpMethod.Get, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.OK == resp.StatusCode) { string refEntitySetNameWithEnityID = refEntityId.Split('/').Last(); string refEntityValue = serviceStatus.RootURL.TrimEnd('/') + @"/" + refEntitySetNameWithEnityID; string refEntityID = refEntitySetNameWithEnityID.Contains("'") ? refEntitySetNameWithEnityID.Split('\'')[1] : refEntitySetNameWithEnityID.Split('(')[1].TrimEnd(')'); JObject navigationRefSet = new JObject(); navigationRefSet.Add(Constants.V4OdataId, refEntityValue); resp = WebHelper.CreateEntity(updateUrl, context.RequestHeaders, navigationRefSet, isMediaType, ref additionalInfosAll); detail = new ExtensionRuleResultDetail(this.Name, updateUrl, HttpMethod.Patch, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.NoContent == resp.StatusCode) { resp = WebHelper.GetEntity(updateUrl); detail = new ExtensionRuleResultDetail(this.Name, updateUrl, HttpMethod.Get, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.OK == resp.StatusCode) { JObject refEntitySet; resp.ResponsePayload.TryToJObject(out refEntitySet); bool created = false; var entries = JsonParserHelper.GetEntries(refEntitySet); if (entries != null) { foreach (JObject entry in entries) { foreach (JProperty prop in entry.Children()) { if (prop.Name.Equals(Constants.V4OdataId)) { created = prop.Value.ToString().Contains(refEntityID); if (created) { passed = true; break; } } } } if (!created) { passed = false; detail.ErrorMessage = string.Format("The HTTP Post to add a reference to a collection-valued navigation property failed."); } } } else { passed = false; detail.ErrorMessage = "HTTP Get to the navigation property reference failed."; } } else { passed = false; detail.ErrorMessage = "HTTP Post to add the navigation property reference failed."; } } else { detail.ErrorMessage = "Can not get the created navigation entity set entity."; } } else { detail.ErrorMessage = "Creating navigation entity failes from above URI."; } } else { detail.ErrorMessage = "Can not get the created entity's navigation property reference collection set from above URI."; } // Restore the service. var resps = WebHelper.DeleteEntities(context.RequestHeaders, additionalInfosAll); } else { detail.ErrorMessage = "Creating the new entity failed for above URI."; } var details = new List<ExtensionRuleResultDetail>() { detail }; info = new ExtensionRuleViolationInfo(new Uri(updateUrl), serviceStatus.ServiceDocument, details); return passed; }
/// <summary> /// Verifies the service implementation feature. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if the service implementation feature passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; 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; var termDocs = TermDocuments.GetInstance(); var serviceStatus = ServiceStatus.GetInstance(); var dFactory = DataFactory.Instance(); var detail1 = new ExtensionRuleResultDetail(this.Name); var detail2 = new ExtensionRuleResultDetail(this.Name); List<string> keyPropertyTypes = new List<string>() { "Edm.Int32", "Edm.Int16", "Edm.Int64", "Edm.Guid", "Edm.String" }; List<string> norPropertyTypes = new List<string>() { "Edm.String" }; List<EntityTypeElement> entityTypeElements = MetadataHelper.GetEntityTypes(serviceStatus.MetadataDocument, 1, keyPropertyTypes, norPropertyTypes, 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 and a normal property with string type, but there is not this entity type in metadata, so can not verify this rule."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1); return passed; } EntityTypeElement entityType = null; foreach (var ele in entityTypeElements) { if (ele.EntityTypeShortName.IsMediaType()) { continue; } var funcs = new List<Func<string, string, string, List<NormalProperty>, List<NavigProperty>, bool>>() { AnnotationsHelper.GetInsertRestrictions, AnnotationsHelper.GetUpdateRestrictions, AnnotationsHelper.GetDeleteRestrictions }; var methods = new List<Func<string, string, List<string>, bool?>>() { SupportiveFeatureHelper.IsSupportBatchOperation }; var restrictions = ele.EntitySetName.GetRestrictions(serviceStatus.MetadataDocument, termDocs.VocCapabilitiesDoc, funcs, null, NavigationRoughType.None, methods); if (!string.IsNullOrEmpty(restrictions.Item1) && null != restrictions.Item2 && restrictions.Item2.Any()) { entityType = ele; break; } } if (null == entityType || string.IsNullOrEmpty(entityType.EntitySetName)) { detail1.ErrorMessage = "The service does not support batch operation."; 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(); var resp = WebHelper.CreateEntity(url, context.RequestHeaders, reqData, false, ref additionalInfos); detail1 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.Created == resp.StatusCode) { string entityId = additionalInfos.Last().EntityId; bool hasEtag = additionalInfos.Last().HasEtag; resp = WebHelper.GetEntity(entityId); if (HttpStatusCode.OK == resp.StatusCode) { JObject entity = JObject.Parse(resp.ResponsePayload); List<string> norPropertyNames = entityType.NormalProperties.Where(norProp => norPropertyTypes.Contains(norProp.PropertyType)).Select(norProp => norProp.PropertyName).ToList(); reqDataStr = dFactory.ConstructUpdatedEntityData(entity, norPropertyNames).ToString(); string boundary = "batch_4e1a76dc-b738-4aa4-9f93-df661d0a4c9f"; string batchReqData = string.Format( @" --batch_4e1a76dc-b738-4aa4-9f93-df661d0a4c9f Content-Type: multipart/mixed; boundary=changeset_77162fcd-b8da-41ac-a9f8-9357efbbd621 --changeset_77162fcd-b8da-41ac-a9f8-9357efbbd621 Content-Type: application/http Content-Transfer-Encoding: binary Content-ID: 1 PATCH {0} HTTP/1.1 " + (hasEtag ? "If-Match: *" : string.Empty) + @" {1} --changeset_77162fcd-b8da-41ac-a9f8-9357efbbd621-- --batch_4e1a76dc-b738-4aa4-9f93-df661d0a4c9f-- ", entityId, reqDataStr); resp = WebHelper.BatchOperation(serviceStatus.RootURL, batchReqData, boundary); detail2 = new ExtensionRuleResultDetail(this.Name, serviceStatus.RootURL + "/$batch", HttpMethod.Post, string.Empty, resp, string.Empty, batchReqData); if (HttpStatusCode.OK == resp.StatusCode) { string expectedData = @"Content-Type: application/http Content-Transfer-Encoding: binary Content-ID: 1 HTTP/1.1 204 No Content "; int index = resp.ResponsePayload.IndexOf("--changesetresponse"); string payload = resp.ResponsePayload.Remove(0, index + 1); if (expectedData == payload.Filtration(new List<string>() { "\nContent-Type:", "\nContent-Transfer-Encoding:", "\nContent-ID:", "\nHTTP/1.1 " })) { passed = true; } else { passed = false; detail2.ErrorMessage = string.Format("The response payload does not accord with the expected pattern as follows:\r\n{0}", expectedData); } } else { passed = false; detail2.ErrorMessage = "The OData service does not return a 200 OK HTTP status code."; } // Restore the service. var resps = WebHelper.DeleteEntities(context.RequestHeaders, additionalInfos); } } else { passed = false; detail1.ErrorMessage = string.Format("Created the new entity failed for above URI with entity data {0}.", reqDataStr); } var details = new List<ExtensionRuleResultDetail>() { detail1, detail2 }.RemoveNullableDetails(); info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details); return passed; }
/// <summary> /// Verifies the service implementation feature. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if the service implementation feature passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; info = null; 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 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(); DataFactory dFactory = DataFactory.Instance(); var detail = new ExtensionRuleResultDetail(this.Name, serviceStatus.RootURL, HttpMethod.Post, string.Empty); string updateUrl = serviceStatus.RootURL; List<string> keyPropertyTypes = new List<string>() { "Edm.Int32", "Edm.Int16", "Edm.Int64", "Edm.Guid", "Edm.String" }; List<string> norPropertyTypes = new List<string>() { "Edm.String" }; List<EntityTypeElement> entityTypeElements = MetadataHelper.GetEntityTypes(serviceStatus.MetadataDocument, 1, keyPropertyTypes, null, NavigationRoughType.None).ToList(); if (null == entityTypeElements || 0 == entityTypeElements.Count) { detail.ErrorMessage = "To verify this rule it expects an entity type with Int32/Int64/Int16/Guid/String key property and a string type normal property, but there is no this entity type in metadata so can not verify this rule."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail); return passed; } EntityTypeElement entityType = null; NormalProperty primitiveProp = null; foreach (var en in entityTypeElements) { foreach(NormalProperty np in en.NormalProperties) { if (!np.IsKey && np.PropertyType.Equals("Edm.String")) { entityType = en; primitiveProp = np; break; } } if(primitiveProp != null) { break; } } if (entityType == null) { detail.ErrorMessage = "To verify this rule it expects an Edm.String type property in an entity, but there is no such entity in metadata. So can not verify this rule."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail); return passed; } string entitySetUrl = entityType.EntitySetName.MapEntitySetNameToEntitySetURL(); updateUrl = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl; if (string.IsNullOrEmpty(entitySetUrl)) { detail.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, detail); return passed; } string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl; var additionalInfos = new List<AdditionalInfo>(); var reqData = dFactory.ConstructInsertedEntityData(entityType.EntitySetName, entityType.EntityTypeShortName, null, out additionalInfos); if (!dFactory.CheckOrAddTheMissingPropertyData(entityType.EntitySetName, primitiveProp.PropertyName, ref reqData)) { detail.ErrorMessage = "The property to update does not exist, and cannot be updated."; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail); return passed; } string reqDataStr = reqData.ToString(); if (reqDataStr.Length > 2) { bool isMediaType = !string.IsNullOrEmpty(additionalInfos.Last().ODataMediaEtag); var resp = WebHelper.CreateEntity(url, context.RequestHeaders, reqData, isMediaType, ref additionalInfos); detail = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.Created == resp.StatusCode) { string entityId = additionalInfos.Last().EntityId; updateUrl = entityId.TrimEnd('/') + "/" + primitiveProp.PropertyName + @"/$value"; bool hasEtag = additionalInfos.Last().HasEtag; resp = WebHelper.GetPropertyValue(updateUrl); detail = new ExtensionRuleResultDetail(this.Name, updateUrl, HttpMethod.Get, string.Empty, resp); if (HttpStatusCode.OK == resp.StatusCode || HttpStatusCode.NoContent == resp.StatusCode) { resp = WebHelper.UpdateAStringProperty(updateUrl, context.RequestHeaders, hasEtag); detail = new ExtensionRuleResultDetail(this.Name, updateUrl, HttpMethod.Put, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.NoContent == resp.StatusCode) { resp = WebHelper.GetPropertyValue(updateUrl); detail = new ExtensionRuleResultDetail(this.Name, updateUrl, HttpMethod.Get, string.Empty, resp, string.Empty, reqDataStr); if (HttpStatusCode.OK == resp.StatusCode) { if (resp.ResponsePayload == Constants.UpdateData) { passed = true; } else { passed = false; detail.ErrorMessage = string.Format("The primitive property in request is not updated."); } } else { passed = false; detail.ErrorMessage = "Can not get the updated entity."; } } else { passed = false; detail.ErrorMessage = "Put the primitive property failed."; } } else { detail.ErrorMessage = "Can not get the created entity from above URI."; } // Restore the service. var resps = WebHelper.DeleteEntities(context.RequestHeaders, additionalInfos); } else { detail.ErrorMessage = "Created the new entity failed for above URI."; } } else { detail.ErrorMessage = "Constructing the testing entity failed."; } var details = new List<ExtensionRuleResultDetail>() { detail }; info = new ExtensionRuleViolationInfo(new Uri(updateUrl), serviceStatus.ServiceDocument, details); return passed; }
public void Execute(ServiceContext context, IEnumerable <Rule> rules, int rulecount, TestComplete ruleresult) { if (context == null) { this.resultProvider.JobCompleted(true); var e = new RuntimeException(new ArgumentNullException("context"), Resource.NullServiceContext); this.LogRuntimeError(e); return; } if (rules == null) { throw new ArgumentNullException("rules"); } int count = 0; try { foreach (var rule in rules) { count++; TestResult result; try { result = RuleExecuter.ExecuteRule(context, rule); } catch (RuntimeException e) { result = TestResult.CreateAbortedResult(rule, context.JobId); e.JobId = context.JobId; e.RuleName = rule.Name; e.DestinationEndpoint = context.Destination.AbsolutePath; this.LogRuntimeError(e); } catch (Exception ex) { if (!ExceptionHelper.IsCatchableExceptionType(ex)) { throw; } result = TestResult.CreateAbortedResult(rule, context.JobId); if (result.Details == null) { result.Details = new List <ExtensionRuleResultDetail>(); } ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(result.RuleName, string.Empty, HttpMethod.Get, "Exception: " + ex.Message); result.Details.Add(detail); detail = new ExtensionRuleResultDetail(result.RuleName, string.Empty, HttpMethod.Get, "StackTrace: " + ex.StackTrace); result.Details.Add(detail); var e = new RuntimeException(ex, null); e.JobId = context.JobId; e.RuleName = rule.Name; e.DestinationEndpoint = context.Destination.AbsolutePath; this.LogRuntimeError(e); bool tryagain = false; if (tryagain) { result = RuleExecuter.ExecuteRule(context, rule); } } if (ruleresult != null) { ruleresult(result, rulecount, ref count); } this.resultProvider.Accept(result); } //this.resultProvider.JobCompleted(errorOccurred); } catch (Exception ex) { if (!ExceptionHelper.IsCatchableExceptionType(ex)) { throw; } this.resultProvider.JobCompleted(true); } }
/// <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); List<string> keyPropertyTypes = new List<string>() { "Edm.Int32", "Edm.Int16", "Edm.Int64", "Edm.Guid", "Edm.String" }; List<EntityTypeElement> entityTypeElements = MetadataHelper.GetEntityTypes(serviceStatus.MetadataDocument, 1, keyPropertyTypes, null, NavigationRoughType.SingleValued).ToList(); if (null == entityTypeElements || 0 == entityTypeElements.Count()) { detail1.ErrorMessage = "To verify this rule it expects an entity type with Int32/Int64/Int16/Guid/String key property, but there is no this entity type in metadata so can not verify this rule. "; info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1); return passed; } EntityTypeElement entityType = null; foreach (var en in entityTypeElements) { var matchEntity = en.EntitySetName.GetRestrictions(serviceStatus.MetadataDocument, termDocs.VocCapabilitiesDoc, new List<Func<string, string, string, List<NormalProperty>, List<NavigProperty>, bool>>() { AnnotationsHelper.GetDeleteRestrictions, AnnotationsHelper.GetInsertRestrictions }); if (!string.IsNullOrEmpty(matchEntity.Item1) && matchEntity.Item2 != null && matchEntity.Item2.Any() && matchEntity.Item3 != null && matchEntity.Item3.Any()) { entityType = en; break; } } 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; } // Create a entity string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl; var keyNames = entityType.KeyProperties; string keyName = keyNames.First().PropertyName; 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, context.RequestHeaders, reqData, isMediaType, ref additionalInfos); detail1 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr); if (resp.StatusCode == HttpStatusCode.Created) { var entityId = additionalInfos.Last().EntityId; var hasEtag = additionalInfos.Last().HasEtag; // Get a individual property except key property string toDeletePropertyName = string.Empty; List<string> properties = MetadataHelper.GetNormalPropertiesNames(serviceStatus.MetadataDocument, entityType.EntityTypeShortName); foreach (string name in properties) { if (!string.Equals(name, keyName)) { toDeletePropertyName = name; break; } } string individualProUrl = entityId + @"/" + toDeletePropertyName; resp = WebHelper.Get(new Uri(individualProUrl), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, serviceStatus.DefaultHeaders); detail2 = new ExtensionRuleResultDetail(this.Name, individualProUrl, HttpMethod.Get, StringHelper.MergeHeaders(Constants.AcceptHeaderJson, serviceStatus.DefaultHeaders), resp); if (resp.StatusCode == HttpStatusCode.OK) { // Delete the individual property resp = WebHelper.DeleteEntity(individualProUrl, context.RequestHeaders, hasEtag); detail3 = new ExtensionRuleResultDetail(this.Name, individualProUrl, HttpMethod.Delete, string.Empty, resp); if (resp.StatusCode == HttpStatusCode.NoContent) { // Check whether the deleted property is set to null if (WebHelper.GetContent(individualProUrl, context.RequestHeaders, out resp)) { detail4 = new ExtensionRuleResultDetail(this.Name, individualProUrl, HttpMethod.Get, string.Empty, resp); JObject jo; resp.ResponsePayload.TryToJObject(out jo); if (jo != null && jo[Constants.Value].Type == JTokenType.Null) { passed = true; } else if (jo == null) { passed = false; detail4.ErrorMessage = "Can not get individual property after deleting it. "; } else if (jo != null && jo[Constants.Value].Type != JTokenType.Null) { passed = false; detail4.ErrorMessage = "The individual property is not set to null after deleting it. "; } } } else { passed = false; detail3.ErrorMessage = "Delete individual property from the created entity failed. "; } } else { passed = false; detail2.ErrorMessage = "Get individual property from the created entity failed. "; } // Delete the entity var resps = WebHelper.DeleteEntities(context.RequestHeaders, additionalInfos); } else { passed = false; detail1.ErrorMessage = "Created the new entity failed for above URI. "; } var details = new List<ExtensionRuleResultDetail>() { detail1, detail2, detail3, detail4 }.RemoveNullableDetails(); info = new ExtensionRuleViolationInfo(this.ErrorMessage, new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details); return passed; }
/// <summary> /// Verifies the service implementation feature. /// </summary> /// <param name="context">The Interop service context</param> /// <param name="info">out parameter to return violation information when rule does not pass</param> /// <returns>true if the service implementation feature passes; false otherwise</returns> public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info) { if (context == null) { throw new ArgumentNullException("context"); } bool? passed = null; info = null; var svcStatus = ServiceStatus.GetInstance(); string entityTypeShortName; var keyProp = MetadataHelper.GetKeyProperty(out entityTypeShortName); if (null == keyProp) { return passed; } string keyPropName = keyProp.Item1; string keyPropType = keyProp.Item2; if (string.IsNullOrEmpty(entityTypeShortName) || string.IsNullOrEmpty(keyPropName) || string.IsNullOrEmpty(keyPropType)) { return passed; } string entitySetUrl = entityTypeShortName.MapEntityTypeShortNameToEntitySetURL(); string url = string.Format("{0}/{1}?$orderby={2} desc", svcStatus.RootURL.TrimEnd('/'), entitySetUrl, keyPropName); var resp = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders); var detail = new ExtensionRuleResultDetail("ServiceImpl_SystemQueryOptionOrderBy", url, HttpMethod.Get, string.Empty); info = new ExtensionRuleViolationInfo(new Uri(url), string.Empty, detail); if (null != resp && HttpStatusCode.OK == resp.StatusCode) { passed = true; } var jObj = JObject.Parse(resp.ResponsePayload); var jArr = jObj.GetValue("value") as JArray; for (int i = 0; i < jArr.Count - 1; i++) { if (!CompareOperationHelper.Compare(jArr[i][keyPropName], jArr[i + 1][keyPropName], keyPropType, ComparerType.Equal | ComparerType.GreaterThan)) { passed = false; break; } } return passed; }
/// <summary> /// Verifies $expand. /// </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 static HttpStatusCode? VerifyExpand(ServiceContext context, out bool? passed, out ExtensionRuleViolationInfo info) { if (context.ServiceVerResult.ExpandResult != null) { info = context.ServiceVerResult.ExpandResult.ViolationInfo; passed = context.ServiceVerResult.ExpandResult.Passed; return context.ServiceVerResult.ExpandResult.ResponseStatusCode; } passed = null; ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(); var expandRestrictions = AnnotationsHelper.GetExpandRestrictions(context.MetadataDocument, context.VocCapabilities); if (string.IsNullOrEmpty(expandRestrictions.Item1) || null == expandRestrictions.Item3 || !expandRestrictions.Item3.Any()) { detail.ErrorMessage = "Cannot find an entity-set which supports $expand system query options."; info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); context.ServiceVerResult.ExpandResult = new ServiceVerificationResult(passed, info); return null; } string entitySet = expandRestrictions.Item1; string navigProp = expandRestrictions.Item3.First().NavigationPropertyName; string url = string.Format("{0}/{1}?$expand={2}", context.ServiceBaseUri, entitySet, navigProp); Response resp = WebHelper.Get(WebRequest.Create(url), RuleEngineSetting.Instance().DefaultMaximumPayloadSize); detail = new ExtensionRuleResultDetail(string.Empty, url, "GET", string.Empty, resp); if (!string.IsNullOrEmpty(resp.ResponsePayload)) { JObject feed; resp.ResponsePayload.TryToJObject(out feed); var entities = JsonParserHelper.GetEntries(feed); foreach (JObject ob in entities) { if (ob[navigProp] == null) { passed = false; detail.ErrorMessage = string.Format("The expanded property {0} does not exist in response payload.", navigProp); break; } else { passed = true; } } } else { passed = false; detail.ErrorMessage = string.Format("Get response failed from above URI."); } info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail); context.ServiceVerResult.ExpandResult = new ServiceVerificationResult(passed, info, resp.StatusCode); return resp.StatusCode; }
/// <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> /// 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 propTypes = new string[1] { "Edm.DateTimeOffset" }; var propNames = MetadataHelper.GetPropertyNames(propTypes, out entityTypeShortName); if (null == propNames || !propNames.Any()) { return passed; } string propName = propNames[0]; 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) { url = string.Format("{0}?$filter={1} le maxdatetime()", url, propName); 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) { passed = true; } else { passed = false; } } return passed; }