/// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;

            // Verify the lambda operator "any".
            HttpStatusCode? statusCode1 = VerificationHelper.VerifyLambdaOperators(context, LambdaOperatorType.Any, out passed, out info);

            if (true != passed)
            {
                if (info != null)
                {
                    info.SetDetailsName(this.Name);
                }

                return passed;
            }

            // Verify the lambda operator "all".
            HttpStatusCode? statusCode2 = VerificationHelper.VerifyLambdaOperators(context, LambdaOperatorType.All, out passed, out info);
            if (info != null)
            {
                info.SetDetailsName(this.Name);
            }

            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;

            HttpStatusCode? statusCode1 = VerificationHelper.VerifyCanonicalFunction(context, CanonicalFunctionType.Supported, out passed, out info);
            if (true != passed)
            {
                if (info != null)
                {
                    info.SetDetailsName(this.Name);
                }
                return passed;
            }

            HttpStatusCode? statusCode2 = VerificationHelper.VerifyCanonicalFunction(context, CanonicalFunctionType.Unsupported, out passed, out info);
            passed = statusCode2 == HttpStatusCode.NotImplemented ? true : false;
            if (info != null)
            {
                info.SetDetailsName(this.Name);
            }

            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            info = null;
            List<ExtensionRuleResultDetail> details = new List<ExtensionRuleResultDetail>();
            ExtensionRuleViolationInfo info1 = null, info2 = null;

            bool? isVerifySortEntitiesOrderByAsc = VerificationHelper.VerifySortEntities(context, SortedType.ASC, out info1);
            bool? isVerifySortEntitiesOrderByDesc = VerificationHelper.VerifySortEntities(context, SortedType.DESC, out info2);
            if (info1 != null)
            {
                details.AddRange(info1.Details);
            }
            if (info2 != null)
            {
                details.AddRange(info2.Details);
            }

            info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, details);
            info.SetDetailsName(this.Name);

            return true == isVerifySortEntitiesOrderByAsc && true == isVerifySortEntitiesOrderByDesc;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;

            HttpStatusCode? statusCode1 = VerificationHelper.VerifySortEntities(context, SortedType.ASC, out passed, out info);
            if (info != null)
            {
                info.SetDetailsName(this.Name);
            }
            if (true != passed)
            {
                return passed;
            }

            HttpStatusCode? statusCode2 = VerificationHelper.VerifySortEntities(context, SortedType.DESC, out passed, out info);
            if (info != null)
            {
                info.SetDetailsName(this.Name);
            }

            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;

            Uri metadataServiceUrl = new Uri(context.Destination.AbsoluteUri.TrimEnd('/') + @"/$metadata" + @"/");
            var req = WebRequest.Create(metadataServiceUrl) as HttpWebRequest;
            Response response = WebHelper.Get(req, RuleEngineSetting.Instance().DefaultMaximumPayloadSize);
            ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name, metadataServiceUrl.AbsoluteUri, "GET", string.Empty, response);

            if (response != null && response.StatusCode == HttpStatusCode.OK && response.ResponsePayload.IsMetadata())
            {
                passed = true;
            }
            else
            {
                passed = false;
                detail.ErrorMessage = "The response is not the metadata service document. Please refer to section 15 of [OData-CSDL].";
            }

            info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail);
            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            var response = WebHelper.Get(context.Destination, string.Empty, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders);
            ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name, context.Destination.AbsoluteUri, "GET", StringHelper.MergeHeaders(string.Empty, context.RequestHeaders), response);

            if (response != null && response.StatusCode != null)
            {
                if (context.PayloadFormat == RuleEngine.PayloadFormat.JsonLight)
                {
                    passed = true;
                }
                else
                {
                    passed = false;
                    detail.ErrorMessage = "Get above URI with accept header 'application/json', the response is not JSON format.";
                }
            }
            else
            {
                passed = false;
                detail.ErrorMessage = String.Format("No response returned from above URI with accept header 'application/json'.");
            }

            info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail);
            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name);

            var restrictions = AnnotationsHelper.GetChangeTracking(context.MetadataDocument, context.VocCapabilities);

            if (string.IsNullOrEmpty(restrictions.Item1) ||
                null == restrictions.Item2 || !restrictions.Item2.Any() ||
                null == restrictions.Item3 || !restrictions.Item3.Any())
            {
                detail.ErrorMessage = "Cannot find an entity-container or any entity-sets which support the change tracking function.";
                info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail);

                return passed;
            }

            string url = string.Format("{0}/{1}", context.ServiceBaseUri, restrictions.Item1);
            List<KeyValuePair<string, string>> requestHeaders = new List<KeyValuePair<string,string>>();

            foreach (KeyValuePair<string, string> kvp in context.RequestHeaders)
            {
                requestHeaders.Add(new KeyValuePair<string, string>(kvp.Key, kvp.Value));
            }

            // Add odata.track-changes preference in request header.
            KeyValuePair<string, string> prefer = new KeyValuePair<string, string>("Prefer", "odata.track-changes");
            requestHeaders.Add(prefer);
            Response response = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, requestHeaders);
            detail = new ExtensionRuleResultDetail(this.Name, url, "GET", StringHelper.MergeHeaders(Constants.V4AcceptHeaderJsonFullMetadata, requestHeaders), response);

            if (response != null && !string.IsNullOrEmpty(response.ResponseHeaders))
            {
                string preferHeader = response.ResponseHeaders.GetHeaderValue("Preference-Applied");

                if (string.IsNullOrEmpty(preferHeader))
                {
                    passed = false;
                    detail.ErrorMessage = "The response header returned by the service does not contain 'odata.track-changes', when request with the header 'Prefer:odata.track-changes'.";
                }
                else if (preferHeader.Contains("odata.track-changes"))
                {
                    passed = true;
                }
            }
            else
            {
                passed = false;
                detail.ErrorMessage = "The service does not support Delta change tracking.";
            }

            info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail);
            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            string selectedName = string.Empty;
            string functionactionName = "forFunctionAction";

            // Use the XPath query language to access the metadata document and get all Namespace and Alias value.
            XElement metadata = XElement.Parse(context.MetadataDocument);
            string xpath = @"//*[local-name()='DataServices']/*[local-name()='Schema']";
            List<string> appropriateNamespace = MetadataHelper.GetPropertyValues(context, xpath, "Namespace");

            // Use the XPath query language to access the metadata document and get all Function names and all Action names.
            xpath = @"//*[local-name()='EntityContainer']/*[local-name()='FunctionImport']";
            List<string> functionImportNames = MetadataHelper.GetPropertyValues(context, xpath, "Name");

            xpath = @"//*[local-name()='EntityContainer']/*[local-name()='ActionImport']";
            List<string> actionImportNames = MetadataHelper.GetPropertyValues(context, xpath, "Name");

            if (!functionImportNames.Contains(functionactionName) && !actionImportNames.Contains(functionactionName))
            {
                selectedName = functionactionName;
            }
            else
            {
                selectedName = functionactionName + "New";
            }

            string url = string.Format("{0}/?$select={1}.{2}", context.Destination, appropriateNamespace[0], selectedName);
            var req = WebRequest.Create(url) as HttpWebRequest;
            var response = WebHelper.Get(req, RuleEngineSetting.Instance().DefaultMaximumPayloadSize);
            ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name, url, "GET", string.Empty, response);

            if (response != null && response.StatusCode != null)
            {
                if (response.StatusCode != HttpStatusCode.OK)
                {
                    passed = true;
                }
                else
                {
                    passed = false;
                    detail.ErrorMessage = "The OData service MUST fail any request that contains actions or functions that it does not understand.";
                }
            }
            else
            {
                passed = false;
                detail.ErrorMessage = String.Format("No response returned from above URI.");
            }

            info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail);
            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            bool? passed = null;
            info = null;
            HttpStatusCode? statusCode = VerificationHelper.VerifyCount(context, out passed, out info);
            if (info != null)
            {
                info.SetDetailsName(this.Name);
            }

            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;

            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;

            ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name);
            detail.ErrorMessage = @"This negative rule is not verified.";
            info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail);

            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;

            var response = WebHelper.Get(context.Destination, Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders);
            ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name, context.Destination.AbsoluteUri, "GET", StringHelper.MergeHeaders(Constants.AcceptHeaderJson, context.RequestHeaders), response);

            if (response != null && response.StatusCode != null)
            {
                // Extracts OData-Version value from ResponseHttpHeaders.
                string oDataVersion = context.ResponseHttpHeaders.GetHeaderValue(Constants.ODataVersion).TrimEnd(';');

                if (!string.IsNullOrEmpty(oDataVersion))
                {
                    float version = float.Parse(oDataVersion);

                    // The minimal OData version of conformance validation is 4.0.
                    if (version >= 4.0)
                    {
                        passed = true;
                    }
                    else
                    {
                        passed = false;
                        detail.ErrorMessage = string.Format(@"The OData version is {0} which should be not less than minimal version 4.0.", version);
                    }
                }
                else
                {
                    passed = false;
                    detail.ErrorMessage = @"Can not get the OData-Version header from response headers.";
                }
            }
            else
            {
                passed = null;
                detail.ErrorMessage = "Cannot get response from above URI.";
            }

            info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail);
            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;
            VerificationHelper.VerifySearch(context, out passed, out info);
            if (info != null)
            {
                info.SetDetailsName(this.Name);
            }

            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;

            string url = context.Destination.AbsoluteUri.TrimEnd('/') + @"/$metadata";
            var response = WebHelper.Get(new Uri(url), string.Empty, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders);
            ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name, url, "GET", StringHelper.MergeHeaders(string.Empty, context.RequestHeaders), response);

            if (response != null && response.StatusCode != null)
            {
                // Get EntityContainer from metadata payload.
                string xpath = @"//*[local-name()='EntityContainer']";
                XElement metadata = XElement.Parse(response.ResponsePayload);
                IEnumerable<XElement> entityContainer = metadata.XPathSelectElements(xpath, ODataNamespaceManager.Instance);
                List<string> propNames = new List<string>();

                foreach (var prop in entityContainer)
                {
                    propNames.Add(prop.Attribute("Name").Value);
                }

                if (propNames.Count > 0)
                {
                    passed = true;
                }
                else
                {
                    passed = false;
                    detail.ErrorMessage = "There is no EntityContainer in metadata document.";
                }
            }
            else
            {
                passed = false;
                detail.ErrorMessage = String.Format("No response returned from above URI.");
            }

            info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail);
            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool svcDocResult = false;
            bool metadataResult = false;
            bool errorResponseResult = false;
            bool feedAndEntryResult = false;
            ExtensionRuleViolationInfo infoForOne = null;
            List<ExtensionRuleResultDetail> details = new List<ExtensionRuleResultDetail>();

            svcDocResult = VerificationHelper.VerifySvcDoc(context, out infoForOne);
            if (infoForOne != null)
            {
                details.AddRange(infoForOne.Details);
            }

            metadataResult = VerificationHelper.VerifyMetadata(context, out infoForOne);
            if (infoForOne != null)
            {
                details.AddRange(infoForOne.Details);
            }

            errorResponseResult = VerificationHelper.VerifyError(context, out infoForOne);
            if (infoForOne != null)
            {
                details.AddRange(infoForOne.Details);
            }

            feedAndEntryResult = VerificationHelper.VerifyFeedAndEntry(context, out infoForOne);
            if (infoForOne != null)
            {
                details.AddRange(infoForOne.Details);
            }

            info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, details);
            info.SetDetailsName(this.Name);

            return svcDocResult && metadataResult && feedAndEntryResult && errorResponseResult;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;

            string url = string.Format("{0}/?$find=*", context.Destination);
            var req = WebRequest.Create(url) as HttpWebRequest;
            Response response = WebHelper.Get(req, RuleEngineSetting.Instance().DefaultMaximumPayloadSize);
            ExtensionRuleResultDetail detail1 = new ExtensionRuleResultDetail(this.Name, url, "GET", string.Empty, response);

            if (response != null && response.StatusCode != null)
            {

                if (response.StatusCode != HttpStatusCode.OK)
                {
                    passed = true;
                }
                else
                {
                    passed = false;
                    detail1.ErrorMessage = "Services SHOULD fail the above URI because it contains query options 'find' which services does not understand.";
                }
            }
            else
            {
                passed = false;
                detail1.ErrorMessage = "No response returned from above URI.";
            }

            info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail1);
            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;
            ServiceStatus serviceStatus = ServiceStatus.GetInstance();
            TermDocuments termDocs = TermDocuments.GetInstance();
            DataFactory dFactory = DataFactory.Instance();
            ExtensionRuleResultDetail detail1 = new ExtensionRuleResultDetail(this.Name);
            ExtensionRuleResultDetail detail2 = new ExtensionRuleResultDetail(this.Name);
            List<string> keyPropertyTypes = new List<string>() { "Edm.Int32", "Edm.Int16", "Edm.Int64", "Edm.Guid", "Edm.String" };
            List<EntityTypeElement> entityTypeElements = MetadataHelper.GetEntityTypes(serviceStatus.MetadataDocument, 1, keyPropertyTypes, null, NavigationRoughType.None).ToList();

            if (null == entityTypeElements || 0 == entityTypeElements.Count())
            {
                detail1.ErrorMessage = "To verify this rule it expects an entity type with Int32/Int64/Int16/Guid/String key property, but there is no this entity type in metadata so can not verify this rule.";
                info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1);

                return passed;
            }

            // To get test entity which is deleteable and insertable
            EntityTypeElement entityType = null;
            foreach (var entityEle in entityTypeElements)
            {
                var matchEntity = entityEle.EntitySetName.GetRestrictions(serviceStatus.MetadataDocument, termDocs.VocCapabilitiesDoc,
                    new List<Func<string, string, string, List<NormalProperty>, List<NavigProperty>, bool>>()
                    {
                        AnnotationsHelper.GetInsertRestrictions, AnnotationsHelper.GetDeleteRestrictions
                    });

                if (!string.IsNullOrEmpty(matchEntity.Item1)
                     && matchEntity.Item2 != null && matchEntity.Item2.Any()
                     && matchEntity.Item3 != null && matchEntity.Item3.Any())
                {
                    entityType = entityEle;
                    break;
                }
            }

            if (null == entityType)
            {
                detail1.ErrorMessage = "To verify this rule it expects an entity type with deleteable and insertable restrictions, but there is no entity type in metadata which is insertable and deleteable.";
                info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1);

                return passed;
            }

            string entitySetUrl = entityType.EntitySetName.MapEntitySetNameToEntitySetURL();
            if (string.IsNullOrEmpty(entitySetUrl))
            {
                detail1.ErrorMessage = string.Format("Cannot find the entity-set URL which is matched with {0}.", entityType.EntityTypeShortName);
                info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1);

                return passed;
            }

            string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl;
            var additionalInfos = new List<AdditionalInfo>();
            var reqData = dFactory.ConstructInsertedEntityData(entityType.EntitySetName, entityType.EntityTypeShortName, null, out additionalInfos);
            string reqDataStr = reqData.ToString();
            bool isMediaType = !string.IsNullOrEmpty(additionalInfos.Last().ODataMediaEtag);
            var resp = WebHelper.CreateEntity(url, reqData, isMediaType, ref additionalInfos);
            detail1 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr);

            // If create successfully, the resource is updatable and deletable.
            if (resp.StatusCode.HasValue && resp.StatusCode == HttpStatusCode.Created)
            {
                // Get feed response.
                resp = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, serviceStatus.DefaultHeaders);
                detail2 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, StringHelper.MergeHeaders(Constants.V4AcceptHeaderJsonFullMetadata, serviceStatus.DefaultHeaders), resp);
                if (resp.StatusCode.HasValue && resp.StatusCode == HttpStatusCode.OK)
                {
                    JObject jo;
                    resp.ResponsePayload.TryToJObject(out jo);
                    var entries = JsonParserHelper.GetEntries(jo);
                    foreach (JObject entry in entries)
                    {
                        if (entry[Constants.V4OdataEditLink] == null)
                        {
                            passed = false;
                            detail2.ErrorMessage = "Not all entities from above URI contain edit links.";
                            break;
                        }
                    }

                    if (passed == null)
                    {
                        passed = true;
                    }
                }
                else
                {
                    passed = false;
                    detail2.ErrorMessage = "Get feed resource failed from above URI.";
                }

                // Restore the service.
                var resps = WebHelper.DeleteEntities(additionalInfos);
            }
            else
            {
                passed = null;
                detail1.ErrorMessage = "Created new entity failed, it is not an updatable resource and can not verify this rule.";
            }

            var details = new List<ExtensionRuleResultDetail>() { detail1, detail2 }.RemoveNullableDetails();
            info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details);

            return passed;
        }
        /// <summary>
        /// Verify Entry.Core.4634
        /// </summary>
        /// <param name="context">Service context</param>
        /// <param name="info">out paramater to return violation information when rule fail</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;

            const string relAttribPrefixName = @"http://docs.oasis-open.org/odata/ns/related/";
            string xpath = string.Format(@"//*[local-name()='EntityType' and @Name='{0}']/*[local-name()='NavigationProperty']", context.EntityTypeShortName);
            XElement metadata = XElement.Parse(context.MetadataDocument);
            var navigProps = metadata.XPathSelectElements(xpath, ODataNamespaceManager.Instance);
            List<string> relURLFullNames = new List<string>();

            foreach (var np in navigProps)
            {
                relURLFullNames.Add(relAttribPrefixName + np.Attribute(@"Name").Value);
            }

            xpath = @"/atom:entry/atom:link[@type='application/atom+xml;type=entry' or @type='application/atom+xml;type=feed']";
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(context.ResponsePayload);
            XmlNodeList linkElements = xmlDoc.SelectNodes(xpath, ODataNamespaceManager.Instance);

            foreach (XmlNode le in linkElements)
            {
                if (relURLFullNames.Contains(le.Attributes["rel"].Value) && Uri.IsWellFormedUriString(le.Attributes["rel"].Value, UriKind.Absolute))
                {
                    passed = true;
                }
                else
                {
                    passed = false;
                    info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload);
                    break;
                }
            }

            return passed;
        }
        /// <summary>
        /// Verify Entry.Core.4668
        /// </summary>
        /// <param name="context">Service context</param>
        /// <param name="info">out paramater to return violation information when rule fail</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;

            var StreamTypeResultList = MetadataHelper.GetAllStreamTypeFromEntry(context.MetadataDocument, context.EntityTypeShortName);

            if (StreamTypeResultList.Count == 0)
            {
                info = null;
                return null;
            }

            XElement xePayload = XElement.Parse(context.ResponsePayload);
            string streamEditref = @"http://docs.oasis-open.org/odata/ns/edit-media/";
            string streamReadref = @"http://docs.oasis-open.org/odata/ns/mediaresource/";

            string editlinkFormat = string.Format("./*[local-name()='link' and @rel='{0}{1}']", streamEditref, @"{0}");
            string readlinkFormat = string.Format("./*[local-name()='link' and @rel='{0}{1}']", streamReadref, @"{0}");
            bool hasLinkNode = false;

            foreach (var xe in StreamTypeResultList)
            {
                string property = xe.GetAttributeValue("Name");

                var xereadlink = xePayload.XPathSelectElement(string.Format(editlinkFormat, property), ODataNamespaceManager.Instance);
                var xeeditlink = xePayload.XPathSelectElement(string.Format(readlinkFormat, property), ODataNamespaceManager.Instance);
                if (xereadlink != null || xeeditlink != null)
                {
                    hasLinkNode = true;
                }
                if (xereadlink != null)
                {
                    if (xereadlink.GetAttributeValue(@"href") == null)
                    {
                        passed = false;
                        break;
                    }
                }

                if (xeeditlink != null)
                {
                    if (xeeditlink.GetAttributeValue(@"href") == null)
                    {
                        passed = false;
                        break;
                    }
                }
            }

            if (hasLinkNode && passed == null)
            {
                passed = true;
            }

            info = new ExtensionRuleViolationInfo(passed == true ? null : this.ErrorMessage, context.Destination, context.ResponsePayload);

            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;
            ServiceStatus serviceStatus = ServiceStatus.GetInstance();
            TermDocuments termDocs = TermDocuments.GetInstance();
            DataFactory dFactory = DataFactory.Instance();
            var detail1 = new ExtensionRuleResultDetail(this.Name, serviceStatus.RootURL, HttpMethod.Post, string.Empty);
            var detail2 = new ExtensionRuleResultDetail(this.Name);
            List<string> keyPropertyTypes = new List<string>() { "Edm.Int32", "Edm.Int16", "Edm.Int64", "Edm.Guid", "Edm.String" };
            List<EntityTypeElement> entityTypeElements = MetadataHelper.GetEntityTypes(serviceStatus.MetadataDocument, 1, keyPropertyTypes, null, NavigationRoughType.None).ToList();
            if (null == entityTypeElements || 0 == entityTypeElements.Count())
            {
                detail1.ErrorMessage = "To verify this rule it expects an entity type with Int32/Int64/Int16/Guid/String key property, but there is no this entity type in metadata so can not verify this rule.";
                info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1);

                return passed;
            }

            // To get test entity which is of media type
            EntityTypeElement entityType = null;
            foreach (var entityEle in entityTypeElements)
            {
                if (MetadataHelper.IsMediaEntity(serviceStatus.MetadataDocument, entityEle.EntityTypeShortName, context))
                {
                    entityType = entityEle;
                    break;
                }
            }

            if (null == entityType)
            {
                detail1.ErrorMessage = "To verify this rule it expects an entity type with deleteable and insertable restrictions, but there is no entity type in metadata which is insertable and deleteable.";
                info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1);

                return passed;
            }

            // Map 'entity-set name' to 'entity-set URL'.
            string entitySetUrl = entityType.EntitySetName.MapEntitySetNameToEntitySetURL();
            if (string.IsNullOrEmpty(entitySetUrl))
            {
                detail1.ErrorMessage = string.Format("Cannot find the entity-set URL which is matched with {0}", entityType.EntityTypeShortName);
                info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1);

                return passed;
            }

            string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl;
            var additionalInfos = new List<AdditionalInfo>();
            var reqData = dFactory.ConstructInsertedEntityData(entityType.EntitySetName, entityType.EntityTypeShortName, null, out additionalInfos);
            string reqDataStr = reqData.ToString();
            var resp = WebHelper.CreateEntity(url, context.RequestHeaders, reqData, true, ref additionalInfos);
            detail1 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr);
            if (resp.StatusCode.HasValue && (HttpStatusCode.Created == resp.StatusCode || HttpStatusCode.NoContent == resp.StatusCode))
            {
                string entityId = additionalInfos.Last().EntityId;
                resp = WebHelper.GetEntity(entityId);
                detail2 = new ExtensionRuleResultDetail(this.Name, entityId, HttpMethod.Get, string.Empty, resp);
                if (resp.StatusCode.HasValue && HttpStatusCode.OK == resp.StatusCode)
                {
                    passed = true;
                }
                else
                {
                    passed = false;
                    detail2.ErrorMessage = "Can not get created entity from above URI.";
                }

                // Restore the service.
                var resps = WebHelper.DeleteEntities(context.RequestHeaders, additionalInfos);
            }
            else
            {
                passed = false;
                detail1.ErrorMessage = "Created the new entity failed for above URI.";
            }

            var details = new List<ExtensionRuleResultDetail>() { detail1, detail2 }.RemoveNullableDetails();
            info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details);

            return passed;
        }
        /// <summary>
        /// Verify Metadata.Core.4446
        /// </summary>
        /// <param name="context">Service context</param>
        /// <param name="info">out parameter to return violation information when rule fail</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;

            // Load MetadataDocument into XMLDOM
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(context.MetadataDocument);

            XmlNodeList labeledElementNodeList = xmlDoc.SelectNodes("//*[local-name()='LabeledElement']");
            XmlNodeList labeledElementAttributeNodeList = xmlDoc.SelectNodes("//@LabeledElement");

            if (labeledElementNodeList.Count > 0)
            {
                if (labeledElementAttributeNodeList.Count == 0)
                {
                    passed = true;
                }
                else
                {
                    passed = false;
                    info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload);
                }
            }

            return passed;
        }
        /// <summary>
        /// Verify Entry.Core.4617
        /// </summary>
        /// <param name="context">Service context</param>
        /// <param name="info">out parameter to return violation information when rule fail</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;

            string qualifiedName = "Edm.";
            List<string> xmlNodeTypes = new List<string>();

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(context.ResponsePayload);
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
            nsmgr.AddNamespace("m", Constants.V3NSMetadata);
            string MeataNS = Constants.V3NSMetadata;
            string DataNs = Constants.V3NSData;

            if (context.Version == ODataVersion.V4)
            {
                nsmgr.AddNamespace("m", Constants.NSMetadata);
                MeataNS = Constants.NSMetadata;
                DataNs = Constants.V4NSData;
            }

            XmlNodeList xmlNodeList = xmlDoc.SelectNodes(@"//m:properties/*", nsmgr);

            foreach (XmlNode xmlNode in xmlNodeList)
            {
                if (xmlNode.NamespaceURI.Equals(DataNs) && xmlNode.Attributes["type", MeataNS] != null)
                {
                    string xmlNodeName = xmlNode.LocalName;

                    if (AtomSchemaHelper.IsBuiltInPrimitiveTypes(xmlNodeName, context, out xmlNodeTypes))
                    {
                        foreach (string xmlNodeType in xmlNodeTypes)
                        {
                            string unqualifiedName = xmlNodeType.Remove(0, qualifiedName.Length);
                            string metadataTypeValue = xmlNode.Attributes["type", MeataNS].Value;

                            if (metadataTypeValue.Equals(unqualifiedName))
                            {
                                passed = true;
                            }
                            else
                            {
                                passed = false;
                                info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload);
                                break;
                            }
                        }

                        if (passed == false)
                        {
                            break;
                        }
                    }
                }
            }

            return passed;
        }
        /// <summary>
        /// Verifies the service implementation feature.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if the service implementation feature passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;
            var svcStatus = ServiceStatus.GetInstance();
            string entityTypeShortName;
            var props = MetadataHelper.GetProperties("Edm.GeographyPoint", 1, out entityTypeShortName);
            if (null == props || !props.Any())
            {
                return passed;
            }

            string propName = props[0].PropertyName;
            string srid = props[0].SRID;
            var entitySetUrl = entityTypeShortName.GetAccessEntitySetURL();
            if (string.IsNullOrEmpty(entitySetUrl))
            {
                return passed;
            }

            string url = svcStatus.RootURL.TrimEnd('/') + "/" + entitySetUrl;
            var resp = WebHelper.Get(new Uri(url), string.Empty, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, svcStatus.DefaultHeaders);
            if (null != resp && HttpStatusCode.OK == resp.StatusCode)
            {
                JObject jObj = JObject.Parse(resp.ResponsePayload);
                JArray jArr = jObj.GetValue(Constants.Value) as JArray;
                var entity = jArr.First as JObject;
                var propVal = entity[propName]["coordinates"] as JArray;
                var pt1 = new Point(Convert.ToDouble(propVal[0]), Convert.ToDouble(propVal[1]));
                var pt2 = new Point(0.0, 0.0);
                var distance = Point.GetDistance(pt1, pt2);
                url = string.Format("{0}?$filter=geo.distance({1}, geography'POINT(0.0 0.0)') ge {2}", url, propName, distance);
                resp = WebHelper.Get(new Uri(url), string.Empty, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, svcStatus.DefaultHeaders);
                var detail = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, string.Empty);
                info = new ExtensionRuleViolationInfo(new Uri(url), string.Empty, detail);
                if (null != resp && HttpStatusCode.OK == resp.StatusCode)
                {
                    jObj = JObject.Parse(resp.ResponsePayload);
                    jArr = jObj.GetValue(Constants.Value) as JArray;
                    foreach (JObject et in jArr)
                    {
                        propVal = et[propName]["coordinates"] as JArray;
                        pt1 = new Point(Convert.ToDouble(propVal[0]), Convert.ToDouble(propVal[1]));
                        pt2 = new Point(0.0, 0.0);
                        var dis = Point.GetDistance(pt1, pt2);
                        passed = dis >= distance;
                    }
                }
                else
                {
                    passed = false;
                }
            }

            return passed;
        }
        /// <summary>
        /// Verifies the service implementation feature.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if the service implementation feature passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;

            ExtensionRuleResultDetail detail = new ExtensionRuleResultDetail(this.Name);
            info = new ExtensionRuleViolationInfo(context.Destination, context.ResponsePayload, detail);
            detail = info.Details[0];

            List<string> supportedPropertyTypes = new List<string>{
                PrimitiveDataTypes.Int16, PrimitiveDataTypes.Int32, PrimitiveDataTypes.Int64,
                PrimitiveDataTypes.Decimal, PrimitiveDataTypes.Double
            };

            var filterRestrictions = AnnotationsHelper.GetFilterRestrictions(context.MetadataDocument, context.VocCapabilities, supportedPropertyTypes,NavigationRoughType.None);

            if (string.IsNullOrEmpty(filterRestrictions.Item1) ||
                null == filterRestrictions.Item2 || !filterRestrictions.Item2.Any())
            {
                detail.ErrorMessage = "Cannot find an appropriate entity-set which supports Less Than system query options in the service.";

                return passed;
            }

            string entitySet = filterRestrictions.Item1;
            string primitivePropName = filterRestrictions.Item2.First().PropertyName;

            string url = string.Format("{0}/{1}", context.ServiceBaseUri, entitySet);
            var resp = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders);

            if (null == resp || HttpStatusCode.OK != resp.StatusCode)
            {
                detail.ErrorMessage = JsonParserHelper.GetErrorMessage(resp.ResponsePayload);

                return passed;
            }

            JObject feed;
            resp.ResponsePayload.TryToJObject(out feed);

            if (feed == null || JTokenType.Object != feed.Type)
            {
                detail.ErrorMessage = "The service does not return a valid response for system query option";
                return passed;
            }

            var entities = JsonParserHelper.GetEntries(feed);
            Int64 propVal = entities[0].Value<Int64>(primitivePropName) - 1;

            string pattern = "{0}/{1}?$filter=(1 add 0) mul {2} sub {3} lt 2";
            url = string.Format(pattern, context.ServiceBaseUri, entitySet, primitivePropName, propVal);
            resp = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, context.RequestHeaders);

            detail.URI = url;
            detail.HTTPMethod = "GET";
            detail.RequestHeaders = StringHelper.MergeHeaders(Constants.AcceptHeaderJson, context.RequestHeaders);
            detail.ResponseStatusCode = resp != null && resp.StatusCode.HasValue ? resp.StatusCode.Value.ToString() : "";
            detail.ResponseHeaders = string.IsNullOrEmpty(resp.ResponseHeaders) ? "" : resp.ResponseHeaders;
            detail.ResponsePayload = string.IsNullOrEmpty(resp.ResponsePayload) ? "" : resp.ResponsePayload;

            if (resp.StatusCode != HttpStatusCode.OK)
            {
                passed = false;
                detail.ErrorMessage = "Request failed with system query option $filter '()'.";
                return passed;
            }

            JObject feed2;
            resp.ResponsePayload.TryToJObject(out feed2);

            if (feed2 == null || JTokenType.Object != feed2.Type)
            {
                passed = false;
                detail.ErrorMessage = "The service does not return a valid response for system query option $filter '()'.";
                return passed;
            }

            var entities2 = JsonParserHelper.GetEntries(feed2).ToList();
            var temp = entities2.FindAll(en => en.Value<Int64>(primitivePropName) - propVal < 2).Select(en => en);

            if (entities2.Count() == temp.Count())
            {
                passed = true;
            }
            else
            {
                passed = false;
                detail.ErrorMessage = "The service does not execute an accurate result with system query option $filter '()'.";
            }

            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;
            ServiceStatus serviceStatus = ServiceStatus.GetInstance();
            TermDocuments termDocs = TermDocuments.GetInstance();
            DataFactory dFactory = DataFactory.Instance();
            ExtensionRuleResultDetail detail1 = new ExtensionRuleResultDetail(this.Name);
            ExtensionRuleResultDetail detail2 = new ExtensionRuleResultDetail(this.Name);
            ExtensionRuleResultDetail detail3 = new ExtensionRuleResultDetail(this.Name);
            List<string> keyPropertyTypes = new List<string>() { "Edm.Int32", "Edm.Int16", "Edm.Int64", "Edm.Guid", "Edm.String" };
            List<EntityTypeElement> entityTypeElements = MetadataHelper.GetEntityTypes(serviceStatus.MetadataDocument, 1, keyPropertyTypes, null, NavigationRoughType.CollectionValued).ToList();

            if (entityTypeElements == null || entityTypeElements.Count == 0)
            {
                detail1.ErrorMessage = "To verify this rule it expects an entity type with Int32/Int64/Int16/Guid/String key property, but there is no this entity type in metadata so can not verify this rule.";
                info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1);

                return passed;
            }

            foreach (var et in entityTypeElements)
            {
                string navigPropName = null;
                string navigPropRelatedEntitySetUrl = null;
                string navigPropRelatedEntityTypeKeyName = null;

                var matchEntity = et.EntitySetName.GetRestrictions(serviceStatus.MetadataDocument, termDocs.VocCapabilitiesDoc,
                    new List<Func<string, string, string, List<NormalProperty>, List<NavigProperty>, bool>>()
                    {
                        AnnotationsHelper.GetDeleteRestrictions, AnnotationsHelper.GetInsertRestrictions
                    });

                if (string.IsNullOrEmpty(matchEntity.Item1)
                    || matchEntity.Item2 == null || !matchEntity.Item2.Any()
                    || matchEntity.Item3 == null || !matchEntity.Item3.Any())
                {
                    continue;
                }

                foreach (var np in matchEntity.Item3)
                {
                    navigPropName = np.NavigationPropertyName;
                    string navigEntityTypeShortName = np.NavigationPropertyType.RemoveCollectionFlag().GetLastSegment();
                    List<NormalProperty> navigKeyProps = MetadataHelper.GetKeyProperties(serviceStatus.MetadataDocument, navigEntityTypeShortName).ToList();

                    if (navigKeyProps.Count == 1 && keyPropertyTypes.Contains(navigKeyProps[0].PropertyType))
                    {
                        navigPropRelatedEntitySetUrl = navigEntityTypeShortName.MapEntityTypeShortNameToEntitySetURL();
                        navigPropRelatedEntityTypeKeyName = navigKeyProps[0].PropertyName;
                        break;
                    }
                }

                if (!string.IsNullOrEmpty(navigPropRelatedEntityTypeKeyName) && !string.IsNullOrEmpty(navigPropRelatedEntitySetUrl))
                {
                    string entitySetUrl = et.EntitySetName.MapEntitySetNameToEntitySetURL();
                    string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl;
                    var additionalInfos = new List<AdditionalInfo>();
                    var reqData = dFactory.ConstructInsertedEntityData(et.EntitySetName, et.EntityTypeShortName, null, out additionalInfos);
                    string reqDataStr = reqData.ToString();
                    bool isMediaType = !string.IsNullOrEmpty(additionalInfos.Last().ODataMediaEtag);
                    var resp = WebHelper.CreateEntity(url, context.RequestHeaders, reqData, isMediaType, ref additionalInfos);
                    detail1 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr);

                    if (resp.StatusCode.HasValue && HttpStatusCode.Created == resp.StatusCode)
                    {
                        string entityId = additionalInfos.Last().EntityId;
                        url = serviceStatus.RootURL.TrimEnd('/') + @"/" + navigPropRelatedEntitySetUrl;
                        resp = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, serviceStatus.DefaultHeaders);
                        detail2 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, StringHelper.MergeHeaders(Constants.V4AcceptHeaderJsonFullMetadata, serviceStatus.DefaultHeaders), resp, string.Empty, reqDataStr);
                        if (null != resp && resp.StatusCode == HttpStatusCode.OK)
                        {
                            JObject feed;
                            resp.ResponsePayload.TryToJObject(out feed);
                            var entities = JsonParserHelper.GetEntries(feed);
                            if (entities.Count > 0)
                            {
                                // Use the HTTP method POST to link the navigation property for an entity.
                                reqDataStr = @"{""" + Constants.V4OdataId + @""" : """ + entities[0][Constants.V4OdataId].ToString() + @"""}";
                                url = string.Format("{0}/{1}/$ref", entityId, navigPropName);
                                resp = WebHelper.CreateEntity(url, reqDataStr);
                                detail3 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr);
                                if (null != resp && resp.StatusCode == HttpStatusCode.NoContent)
                                {
                                    passed = true;
                                }
                                else
                                {
                                    passed = false;
                                    detail3.ErrorMessage = "Created the new entity failed for above URI.";
                                }
                            }
                        }
                        else
                        {
                            passed = false;
                            detail2.ErrorMessage = "Get entity failed from above URI.";
                        }

                        // Restore the service.
                        var resps = WebHelper.DeleteEntities(context.RequestHeaders, additionalInfos);
                    }
                    else
                    {
                        passed = false;
                        detail1.ErrorMessage = "Created the new entity failed for above URI.";
                    }
                }

                if (false == passed)
                {
                    break;
                }
            }

            var details = new List<ExtensionRuleResultDetail>() { detail1, detail2, detail3 }.RemoveNullableDetails();
            info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details);

            return passed;
        }
        /// <summary>
        /// Verify Common.Core.4038
        /// </summary>
        /// <param name="context">Service context</param>
        /// <param name="info">out parameter to return violation information when rule fail</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;

            string OdataNextLink = Constants.V4OdataNextLink;

            if (context.Version == ODataVersion.V3)
            {
                OdataNextLink = Constants.OdataNextLink;
            }

            string OdataDeltaLink = Constants.V4OdataDeltaLink;

            if (context.Version == ODataVersion.V3)
            {
                OdataDeltaLink = Constants.V4OdataDeltaLink;
            }

            // Verify whether odata.nextLink annotation in response.
            bool isnextLinkExist = JsonParserHelper.IsSpecifiedAnnotationExist(context, OdataNextLink);

            // Verify whether odata.deltaLink annotation in response.
            bool isdeltaLinkExist = JsonParserHelper.IsSpecifiedAnnotationExist(context, OdataDeltaLink);

            // Response must not have both an odata.deltaLink annotation and an odata.nextLink annotation.
            if (isnextLinkExist && isdeltaLinkExist)
            {
                passed = false;
            }
            else
            {
                passed = true;
            }

            return passed;
        }
        /// <summary>
        /// Verify Metadata.Core.4120
        /// </summary>
        /// <param name="context">Service context</param>
        /// <param name="info">out parameter to return violation information when rule fail</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;
            var metadata = XElement.Parse(context.MetadataDocument);
            string xPath = "//*[local-name()='NavigationProperty']";
            var navigationPropertyElems = metadata.XPathSelectElements(xPath, ODataNamespaceManager.Instance)
                .Where(np => null != np.Attribute("Partner") && null != np.Attribute("Type") && null != np.Attribute("Name"))
                .Select(np => np);
            if (null != navigationPropertyElems && navigationPropertyElems.Any())
            {
                foreach (var navigationPropertyElem in navigationPropertyElems)
                {
                    string navigationPropertyName = navigationPropertyElem.GetAttributeValue("Name");
                    string typeShortName1 = navigationPropertyElem.GetAttributeValue("Type").RemoveCollectionFlag().GetLastSegment();
                    string partnerNavigationPropertyName1 = navigationPropertyElem.GetAttributeValue("Partner");
                    xPath = string.Format("//*[(local-name()='EntityType' or local-name()='ComplexType') and @Name='{0}']/*[local-name()='NavigationProperty' and @Name='{1}']", typeShortName1, partnerNavigationPropertyName1);
                    var npElem = metadata.XPathSelectElement(xPath, ODataNamespaceManager.Instance);
                    if (null != npElem.Parent)
                    {
                        var parentElem = npElem.Parent;
                        var derivedList = parentElem.GetAttributeValue("Name").GetEntityTypeShortNamesFromDerivedType();
                        if (!derivedList.Any() && "ComplexType" != parentElem.Name.LocalName)
                        {
                            string partnerNavigationPropertyName2 = null != npElem.Attribute("Partner") ? npElem.GetAttributeValue("Partner") : string.Empty;
                            if (partnerNavigationPropertyName2 == navigationPropertyName)
                            {
                                passed = true;
                            }
                            else
                            {
                                passed = false;
                                break;
                            }
                        }
                    }
                }
            }

            info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload);

            return passed;
        }
        /// <summary>
        /// Verify rule logic
        /// </summary>
        /// <param name="context">Service context</param>
        /// <param name="info">out parameter to return violation information when rule fail</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;

            JObject entry;
            context.ResponsePayload.TryToJObject(out entry);
            var o = (JObject)entry;
            var jProps = o.Children();

            string odataIdName = Constants.V4OdataId;
            if (context.Version == ODataVersion.V3)
            {
                odataIdName = Constants.OdataId;
            }

            foreach (JProperty jProp in jProps)
            {
                // Whether odata.id exist in minimal metadata cases.
                if (jProp.Name.Contains(odataIdName))
                {
                    // If odata.id exist in minimal metadata, the value of odata.id must deviate from the canonical URL of the entity.
                    if (!jProp.Value.ToString().StripOffDoubleQuotes().Equals(context.DestinationBasePath))
                    {
                        passed = true;
                        break;
                    }
                    else
                    {
                        passed = false;
                        info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload);
                        break;
                    }
                }
            }

            return passed;
        }
        /// <summary>
        /// Verifies the extension rule.
        /// </summary>
        /// <param name="context">The Interop service context</param>
        /// <param name="info">out parameter to return violation information when rule does not pass</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;
            ServiceStatus serviceStatus = ServiceStatus.GetInstance();
            TermDocuments termDocs = TermDocuments.GetInstance();
            DataFactory dFactory = DataFactory.Instance();
            var detail1 = new ExtensionRuleResultDetail(this.Name);
            var detail2 = new ExtensionRuleResultDetail(this.Name);
            var detail3 = new ExtensionRuleResultDetail(this.Name);
            var detail4 = new ExtensionRuleResultDetail(this.Name);
            var detail5 = new ExtensionRuleResultDetail(this.Name);
            var detail6 = new ExtensionRuleResultDetail(this.Name);
            var entityType = MetadataHelper.GetConcurrencyEntityType(serviceStatus.MetadataDocument);
            if (null == entityType)
            {
                detail1.ErrorMessage = "Cannot find an entity which contains a concurrency property in the service.";
                info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail1);

                return passed;
            }

            var normalPropNames = entityType.NormalProperties.Where(np => "Edm.String" == np.PropertyType && !np.IsKey).Select(np => np.PropertyName);
            if (normalPropNames.Any())
            {
                string entitySetUrl = entityType.EntitySetName.MapEntitySetNameToEntitySetURL();
                string url = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl;
                var additionalInfos = new List<AdditionalInfo>();
                var reqData = dFactory.ConstructInsertedEntityData(entityType.EntitySetName, entityType.EntityTypeShortName, null, out additionalInfos);
                string reqDataStr = reqData.ToString();
                bool isMediaType = !string.IsNullOrEmpty(additionalInfos.Last().ODataMediaEtag);
                var resp = WebHelper.CreateEntity(url, reqData, isMediaType, ref additionalInfos);
                detail1 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr);

                if (HttpStatusCode.Created == resp.StatusCode)
                {
                    var entityId = additionalInfos.Last().EntityId;
                    var hasEtag = additionalInfos.Last().HasEtag;
                    if (!hasEtag)
                    {
                        detail1.ErrorMessage = "The new inserted entity does not contain an @odata.etag annotation.";
                        info = new ExtensionRuleViolationInfo(new Uri(entityId), resp.ResponsePayload, detail2);

                        return passed;
                    }

                    resp = WebHelper.GetEntity(entityId, serviceStatus.DefaultHeaders);
                    detail2 = new ExtensionRuleResultDetail(this.Name, entityId, HttpMethod.Get, StringHelper.MergeHeaders(string.Empty, serviceStatus.DefaultHeaders), resp);
                    if (HttpStatusCode.OK == resp.StatusCode)
                    {
                        reqDataStr = dFactory.ConstructUpdatedEntityData(reqData, normalPropNames).ToString();
                        var header = new KeyValuePair<string, string>("If-Match", additionalInfos.Last().ODataEtag);
                        var headers = new List<KeyValuePair<string, string>>() { header };
                        resp = WebHelper.UpdateEntity(entityId, reqDataStr, HttpMethod.Patch, headers);
                        detail3 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Patch, StringHelper.MergeHeaders(string.Empty, headers), resp, string.Empty, reqDataStr);
                        if (HttpStatusCode.NoContent == resp.StatusCode)
                        {
                            resp = WebHelper.GetEntity(entityId, serviceStatus.DefaultHeaders);
                            detail4 = new ExtensionRuleResultDetail(this.Name, entityId, HttpMethod.Get, StringHelper.MergeHeaders(string.Empty, serviceStatus.DefaultHeaders), resp);
                            if (HttpStatusCode.OK == resp.StatusCode)
                            {
                                resp = WebHelper.DeleteEntity(entityId, hasEtag);
                                detail5 = new ExtensionRuleResultDetail(this.Name, entityId, HttpMethod.Delete, StringHelper.MergeHeaders(string.Empty, new List<KeyValuePair<string, string>>() { header }), resp);
                                if (HttpStatusCode.NoContent == resp.StatusCode)
                                {
                                    resp = WebHelper.GetEntity(entityId);
                                    detail6 = new ExtensionRuleResultDetail(this.Name, entityId, HttpMethod.Get, string.Empty, resp);
                                    if (HttpStatusCode.NotFound == resp.StatusCode)
                                    {
                                        passed = true;
                                    }
                                    else
                                    {
                                        passed = false;
                                        detail6.ErrorMessage = "It still can get the deleted entity from above URI.";
                                    }
                                }
                                else
                                {
                                    passed = false;
                                    detail5.ErrorMessage = "Delete entity failed.";
                                }
                            }
                            else
                            {
                                passed = false;
                                detail4.ErrorMessage = "Can not get the created entity from above URI.";
                            }
                        }
                        else
                        {
                            passed = false;
                            detail3.ErrorMessage = "Update entity failed.";
                        }
                    }
                }
                else
                {
                    passed = false;
                    detail1.ErrorMessage = "Created the new entity failed for above URI.";
                }
            }

            var details = new List<ExtensionRuleResultDetail>()
            {
                detail1, detail2, detail3, detail4, detail5, detail6
            }.RemoveNullableDetails();
            info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details);

            return passed;
        }
        /// <summary>
        /// Verify Metadata.Core.4265
        /// </summary>
        /// <param name="context">Service context</param>
        /// <param name="info">out parameter to return violation information when rule fail</param>
        /// <returns>true if rule passes; false otherwise</returns>
        public override bool? Verify(ServiceContext context, out ExtensionRuleViolationInfo info)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            bool? passed = null;
            info = null;
            var metadata = XElement.Parse(context.MetadataDocument);
            string xPath = "//*[local-name()='Function']";
            var functionElems = metadata.XPathSelectElements(xPath, ODataNamespaceManager.Instance);
            if (null != functionElems && functionElems.Any())
            {
                foreach (var functionElem in functionElems)
                {
                    if (null != functionElem.Attribute("Name"))
                    {
                        string nameAttribVal = functionElem.GetAttributeValue("Name");
                        if (nameAttribVal.IsSimpleIdentifier())
                        {
                            passed = true;
                        }
                        else
                        {
                            passed = false;
                            break;
                        }
                    }
                    else
                    {
                        passed = false;
                        break;
                    }
                }
            }

            info = new ExtensionRuleViolationInfo(this.ErrorMessage, context.Destination, context.ResponsePayload);

            return passed;
        }
Example #31
0
 public ServiceVerificationResult(bool?passed, ExtensionRuleViolationInfo violationInfo, HttpStatusCode?responseStatusCode = null)
 {
     Passed             = passed;
     ViolationInfo      = violationInfo;
     ResponseStatusCode = responseStatusCode;
 }