예제 #1
0
        /// <summary>
        /// Asserts whether any properties of an entity-type matches the specified conditions.
        /// </summary>
        /// <param name="entityType">An entity-type.</param>
        /// <param name="containedKeyPropSum">Limits the contained key properties' sum of an entity-type.</param>
        /// <param name="containedKeyPropTypes">Limits the contained key properties' types of an entity-type.</param>
        /// <param name="containedNormalPropTypes">Limits contained normal properties' types of an entity-type.</param>
        /// <param name="containedNavigRoughType">Limits the contained navigation properties' rough-type of an entity-type.</param>
        /// <returns>Returns the decision outcome.</returns>
        public static bool EntityTypeAnyPropertiesMeetsSpecifiedConditions(
            EntityTypeElement entityType,
            uint?containedKeyPropSum,
            IEnumerable <string> containedKeyPropTypes,
            IEnumerable <string> containedNormalPropTypes,
            NavigationRoughType containedNavigRoughType)
        {
            if (entityType == null)
            {
                return(false);
            }

            if (null != containedKeyPropSum)
            {
                if (containedKeyPropSum != entityType.KeyProperties.Count())
                {
                    return(false);
                }
            }

            if (null != containedKeyPropTypes)
            {
                var appropriateKeyProps = entityType.KeyProperties
                                          .Where(keyProp => containedKeyPropTypes.Contains(keyProp.PropertyType))
                                          .Select(keyProp => keyProp);

                if (0 == appropriateKeyProps.Count())
                {
                    return(false);
                }
            }

            if (null != containedNormalPropTypes)
            {
                var appropriateNormalProps = entityType.NormalProperties
                                             .Where(norProp => containedNormalPropTypes.Contains(norProp.PropertyType))
                                             .Select(norProp => norProp);

                if (0 == appropriateNormalProps.Count())
                {
                    return(false);
                }
            }

            if (NavigationRoughType.None != containedNavigRoughType)
            {
                var appropriateNavigProps = entityType.NavigationProperties
                                            .Where(navProp => containedNavigRoughType == navProp.NavigationRoughType)
                                            .Select(navProp => navProp);

                if (0 == appropriateNavigProps.Count())
                {
                    return(false);
                }
            }

            return(true);
        }
        /// <summary>
        /// Asserts whether any properties of an entity-type matches the specified conditions.
        /// </summary>
        /// <param name="entityType">An entity-type.</param>
        /// <param name="containedKeyPropSum">Limits the contained key properties' sum of an entity-type.</param>
        /// <param name="containedKeyPropTypes">Limits the contained key properties' types of an entity-type.</param>
        /// <param name="containedNormalPropTypes">Limits contained normal properties' types of an entity-type.</param>
        /// <param name="containedNavigRoughType">Limits the contained navigation properties' rough-type of an entity-type.</param>
        /// <returns>Returns the decision outcome.</returns>
        public static bool EntityTypeAnyPropertiesMeetsSpecifiedConditions(
            EntityTypeElement entityType,
            uint? containedKeyPropSum,
            IEnumerable<string> containedKeyPropTypes,
            IEnumerable<string> containedNormalPropTypes,
            NavigationRoughType containedNavigRoughType)
        {
            if (entityType == null)
            {
                return false;
            }

            if (null != containedKeyPropSum)
            {
                if (containedKeyPropSum != entityType.KeyProperties.Count())
                {
                    return false;
                }
            }

            if (null != containedKeyPropTypes)
            {
                var appropriateKeyProps = entityType.KeyProperties
                    .Where(keyProp => containedKeyPropTypes.Contains(keyProp.PropertyType))
                    .Select(keyProp => keyProp);

                if (0 == appropriateKeyProps.Count())
                {
                    return false;
                }
            }

            if (null != containedNormalPropTypes)
            {
                var appropriateNormalProps = entityType.NormalProperties
                    .Where(norProp => containedNormalPropTypes.Contains(norProp.PropertyType))
                    .Select(norProp => norProp);

                if (0 == appropriateNormalProps.Count())
                {
                    return false;
                }
            }

            if (NavigationRoughType.None != containedNavigRoughType)
            {
                var appropriateNavigProps = entityType.NavigationProperties
                    .Where(navProp => containedNavigRoughType == navProp.NavigationRoughType)
                    .Select(navProp => navProp);

                if (0 == appropriateNavigProps.Count())
                {
                    return false;
                }
            }

            return true;
        }
예제 #3
0
        /// <summary>
        /// Initializes the NavigProperty class.
        /// </summary>
        /// <param name="navigPropName"></param>
        /// <param name="navigPropType"></param>
        /// <param name="navigPropPartner"></param>
        public NavigProperty(string navigPropName, string navigPropType, string navigPropPartner)
        {
            if (string.IsNullOrEmpty(navigPropName))
            {
                throw new ArgumentNullException("navigPropName", "The value of the input parameter 'navigPropName' MUST NOT be null or empty.");
            }

            if (string.IsNullOrEmpty(navigPropType))
            {
                throw new ArgumentNullException("navigPropType", "The value of the input parameter 'navigPropType' MUST NOT be null or empty.");
            }

            this.navigationPropertyName = navigPropName;
            this.navigationPropertyType = navigPropType;
            this.navigationPropertyPartner = navigPropPartner;
            this.navigationRoughType =
                this.navigationPropertyType.StartsWith(@"Collection(") && this.navigationPropertyType.EndsWith(@")") ?
                Helper.NavigationRoughType.CollectionValued : Helper.NavigationRoughType.SingleValued;
        }
        /// <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;
            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"
            };
            var entityTypeElements = MetadataHelper.GetEntityTypes(serviceStatus.MetadataDocument, 1, keyPropertyTypes, null, NavigationRoughType.None);

            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);
            }

            string entitySet = string.Empty;
            string navigProp = string.Empty;
            NavigationRoughType navigRoughType = NavigationRoughType.None;
            EntityTypeElement   entityType     = new EntityTypeElement();

            foreach (var en in entityTypeElements)
            {
                if (!string.IsNullOrEmpty(en.EntitySetName) && en.NavigationProperties.Count > 0)
                {
                    foreach (NavigProperty np in en.NavigationProperties)
                    {
                        string npTypeFullName = np.NavigationPropertyType.RemoveCollectionFlag();

                        XmlDocument metadata = new XmlDocument();
                        metadata.LoadXml(context.MetadataDocument);
                        if (context.ContainsExternalSchema)
                        {
                            metadata.LoadXml(context.MergedMetadataDocument);
                        }
                        XmlNode npXmlNode;
                        MetadataHelper.GetTypeNode(npTypeFullName, metadata, out npXmlNode);
                        if (!(npXmlNode.Attributes["HasStream"] != null ? npXmlNode.Attributes["HasStream"].Value.Equals("true") : false))
                        {
                            navigProp      = np.NavigationPropertyName;
                            navigRoughType = np.NavigationRoughType;
                            entityType     = en;
                            entitySet      = en.EntitySetName;
                            break;
                        }
                    }

                    if (!string.IsNullOrEmpty(entitySet))
                    {
                        break;
                    }
                }
            }

            if (string.IsNullOrEmpty(entitySet) || string.IsNullOrEmpty(navigProp))
            {
                detail.ErrorMessage = "Cannot find an entity-set URL which can be execute the deep insert operation on it.";
                info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail);

                return(passed);
            }

            string url             = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySet;
            var    additionalInfos = new List <AdditionalInfo>();
            var    reqData         = dFactory.ConstructInsertedEntityData(entityType.EntitySetName, entityType.EntityTypeShortName, new List <string>()
            {
                navigProp
            }, out 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)
            {
                var    mainEntityID = additionalInfos.Last().EntityId;
                string entityId     = additionalInfos.First().EntityId;

                string refUrl = mainEntityID.TrimEnd('/') + "/" + navigProp + "/$ref";
                string refEntitySetNameWithEnityID = entityId.Split('/').Last();
                string refEntityValue = serviceStatus.RootURL.TrimEnd('/') + @"/" + refEntitySetNameWithEnityID;
                string refEntityID    = refEntitySetNameWithEnityID.Contains("'") ? refEntitySetNameWithEnityID.Split('\'')[1] : refEntitySetNameWithEnityID.Split('(')[1].TrimEnd(')');

                resp   = WebHelper.GetEntity(mainEntityID);
                detail = new ExtensionRuleResultDetail(this.Name, mainEntityID, HttpMethod.Get, string.Empty, resp, string.Empty, reqDataStr);

                if (HttpStatusCode.OK == resp.StatusCode && additionalInfos.Count > 1)
                {
                    resp   = WebHelper.GetEntity(refUrl);
                    detail = new ExtensionRuleResultDetail(this.Name, refUrl, HttpMethod.Get, string.Empty, resp, string.Empty, reqDataStr);

                    if (HttpStatusCode.OK == resp.StatusCode)
                    {
                        JObject refPayload;
                        resp.ResponsePayload.TryToJObject(out refPayload);
                        bool created = false;

                        if (navigRoughType == NavigationRoughType.CollectionValued)
                        {
                            var entries = JsonParserHelper.GetEntries(refPayload);

                            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;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            foreach (JProperty prop in refPayload.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 deep insert failed to add a reference to a collection-valued navigation property failed.");
                        }
                    }
                }
                else
                {
                    passed = false;
                    detail.ErrorMessage = "Can not get the created entity. ";
                }

                // Restore the service.
                var resps = WebHelper.DeleteEntities(context.RequestHeaders, additionalInfos);
            }
            else
            {
                passed = false;
                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>
        /// Gets filter restrictions.
        /// </summary>
        /// <param name="metadataDoc">The metadata document.</param>
        /// <param name="vocCapabilitiesDoc">The vocabulary-capabilities document.</param>
        /// <param name="primitiveTypes">The expected primitive types' list.</param>
        /// <param name="navigationType">The expected navigation rough type.</param>
        /// <param name="methods">The delegate function to filter other term restrictions with the type 'Core.Tag'.</param>
        /// <returns>Returns an appropriate tuple element which supports filter restrictions.</returns>
        public static Tuple<string, List<NormalProperty>, List<NavigProperty>> GetFilterRestrictions(
            string metadataDoc,
            string vocCapabilitiesDoc,
            List<string> primitiveTypes = null,
            NavigationRoughType navigationType = NavigationRoughType.None,
            List<Func<string, string, List<string>, bool?>> methods = null)
        {
            if (string.IsNullOrEmpty(metadataDoc) ||
                !metadataDoc.IsXmlPayload() ||
                string.IsNullOrEmpty(vocCapabilitiesDoc) ||
                !vocCapabilitiesDoc.IsXmlPayload())
            {
                return new Tuple<string, List<NormalProperty>, List<NavigProperty>>(string.Empty, new List<NormalProperty>(), new List<NavigProperty>());
            }

            var feeds = MetadataHelper.GetFeeds(metadataDoc);

            if (!feeds.Any())
            {
                return new Tuple<string, List<NormalProperty>, List<NavigProperty>>(string.Empty, new List<NormalProperty>(), new List<NavigProperty>());
            }

            string entitySet = string.Empty;
            List<NormalProperty> normalProps = new List<NormalProperty>();
            List<NavigProperty> navigationProps = new List<NavigProperty>();

            foreach (var f in feeds)
            {
                string entityTypeShortName = f.MapEntitySetNameToEntityTypeShortName();
                bool flag = true;

                if (null != methods && methods.Any())
                {
                    foreach (var func in methods)
                    {
                        if (true != func(f, metadataDoc, new List<string>() { vocCapabilitiesDoc }))
                        {
                            flag = false;
                            break;
                        }
                    }
                }

                if (string.IsNullOrEmpty(entityTypeShortName) || !flag)
                {
                    continue;
                }

                var props = MetadataHelper.GetNormalProperties(metadataDoc, entityTypeShortName).ToList();
                var nprops = MetadataHelper.GetNavigationProperties(metadataDoc, entityTypeShortName).ToList();

                if (null == props || !props.Any() || null == nprops || !nprops.Any())
                {
                    continue;
                }

                if (null != primitiveTypes && primitiveTypes.Any() &&
                    !AnnotationsHelper.IsSuitableProperty(props, primitiveTypes))
                {
                    continue;
                }

                if (NavigationRoughType.None != navigationType &&
                    !AnnotationsHelper.IsSuitableNavigationProperty(nprops, navigationType))
                {
                    continue;
                }

                if (AnnotationsHelper.GetFilterRestrictions(f, metadataDoc, vocCapabilitiesDoc, props, nprops) && props.Any() && nprops.Any())
                {
                    entitySet = f;
                    normalProps.AddRange(props);
                    navigationProps.AddRange(nprops);

                    break;
                }
            }

            return new Tuple<string, List<NormalProperty>, List<NavigProperty>>(entitySet, normalProps, navigationProps);
        }
        /// <summary>
        /// Verify whether the navigation properties' list contain specified navigation rough type.
        /// </summary>
        /// <param name="navigProperties">The navigation properties.</param>
        /// <param name="navigRoughType">The navigation rough type.</param>
        /// <returns>Returns the boolean result.</returns>
        private static bool IsSuitableNavigationProperty(List<NavigProperty> navigProperties, NavigationRoughType navigRoughType)
        {
            bool flag = false;
            List<NavigProperty> nprops = new List<NavigProperty>();

            foreach (var np in navigProperties)
            {
                if (navigRoughType == np.NavigationRoughType)
                {
                    flag = true;
                    nprops.Add(np);
                }
            }

            navigProperties.Clear();
            navigProperties.AddRange(nprops);

            return flag;
        }
        /// <summary>
        /// Filter out unsuitable navigation properties.
        /// </summary>
        /// <param name="navigationRoughType">The navigation rough type.</param>
        /// <param name="restrictions">All the appropriate entity-sets which match the specified restrictions.</param>
        /// (Note: This parameter is a reference parameter, but without 'ref' flag before its type.)</param>
        /// <returns>Returns whether find any entity-sets match the specified restrictions or not.</returns>
        public static bool IsSuitableNavigationProperty(
            NavigationRoughType navigationRoughType,
            ref Dictionary<string, Tuple<List<NormalProperty>, List<NavigProperty>>> restrictions)
        {
            if (NavigationRoughType.None == navigationRoughType || null == restrictions || !restrictions.Any())
            {
                return false;
            }

            var result = new Dictionary<string, Tuple<List<NormalProperty>, List<NavigProperty>>>();

            foreach (var r in restrictions)
            {
                List<NavigProperty> nprops = new List<NavigProperty>();

                foreach (var np in r.Value.Item2)
                {
                    if (navigationRoughType == np.NavigationRoughType)
                    {
                        nprops.Add(np);
                    }
                }

                result.Add(r.Key, new Tuple<List<NormalProperty>, List<NavigProperty>>(r.Value.Item1, nprops));
            }

            restrictions = result;

            return result.Any() ? true : false;
        }
예제 #8
0
        /// <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;
            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"
            };
            var entityTypeElements = MetadataHelper.GetEntityTypes(serviceStatus.MetadataDocument, 1, keyPropertyTypes, null, NavigationRoughType.None);

            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);
            }

            string entitySet     = string.Empty;
            string navigPropName = string.Empty;
            NavigationRoughType navigPropRoughType = NavigationRoughType.None;
            EntityTypeElement   entityType         = new EntityTypeElement();

            foreach (var en in entityTypeElements)
            {
                entitySet = en.EntitySetName;
                var funcs = new List <Func <string, string, string, List <NormalProperty>, List <NavigProperty>, bool> >()
                {
                    AnnotationsHelper.GetExpandRestrictions, AnnotationsHelper.GetInsertRestrictions, AnnotationsHelper.GetDeleteRestrictions
                };

                var restrictions = entitySet.GetRestrictions(serviceStatus.MetadataDocument, termDocs.VocCapabilitiesDoc, funcs, null, NavigationRoughType.None);
                if (!string.IsNullOrEmpty(restrictions.Item1) &&
                    null != restrictions.Item2 && restrictions.Item2.Any() &&
                    null != restrictions.Item3 && restrictions.Item3.Any())
                {
                    navigPropName      = restrictions.Item3.First().NavigationPropertyName;
                    navigPropRoughType = restrictions.Item3.First().NavigationRoughType;
                    entityType         = en;
                    break;
                }
            }

            if (string.IsNullOrEmpty(entitySet) || string.IsNullOrEmpty(navigPropName))
            {
                detail.ErrorMessage = "Cannot find an entity set whose entity type has navigation property.";
                info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, detail);

                return(passed);
            }

            string entitySetUrl       = entityType.EntitySetName.MapEntitySetNameToEntitySetURL();
            string updateUrl          = serviceStatus.RootURL;
            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('/') + "/" + navigPropName;
                updateUrl = entityId.TrimEnd('/') + "/" + navigPropName + "/$ref";
                bool hasEtag = additionalInfos.Last().HasEtag;

                string navigPropType          = MetadataHelper.GetNavigPropertyTypeFromMetadata(navigPropName, entityType.EntityTypeShortName, serviceStatus.MetadataDocument);
                string navigPropTypeShortName = string.Empty;
                if (navigPropRoughType == NavigationRoughType.CollectionValued)
                {
                    navigPropTypeShortName = navigPropType.Substring(navigPropType.IndexOf("(")).GetLastSegment().TrimEnd(')');
                }
                else
                {
                    navigPropTypeShortName = navigPropType.GetLastSegment();
                }
                string nEntitySetName = navigPropName.MapNavigationPropertyNameToEntitySetName(entityType.EntityTypeShortName);
                string nEntitySetUrl  = nEntitySetName.MapEntitySetNameToEntitySetURL();
                nEntitySetUrl = serviceStatus.RootURL.TrimEnd('/') + @"/" + nEntitySetUrl;

                reqData = dFactory.ConstructInsertedEntityData(nEntitySetName, navigPropTypeShortName, null, out additionalInfos);

                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);
                detail.URI                = nEntitySetUrl;
                detail.ResponsePayload    = resp.ResponsePayload;
                detail.ResponseHeaders    = resp.ResponseHeaders;
                detail.HTTPMethod         = "GET";
                detail.ResponseStatusCode = resp.StatusCode.ToString();

                if (HttpStatusCode.Created == resp.StatusCode)
                {
                    foreach (AdditionalInfo a in additionalInfos)
                    {
                        additionalInfosAll.Add(a);
                    }

                    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 addedNavigRefUrl = string.Empty;

                        if (navigPropRoughType == NavigationRoughType.CollectionValued)
                        {
                            addedNavigRefUrl = updateUrl + @"?$id=" + refEntityId;

                            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);
                        }
                        else if (navigPropRoughType == NavigationRoughType.SingleValued)
                        {
                            addedNavigRefUrl = updateUrl;

                            string refEntityIdUrl = additionalInfos.Last().EntityId;

                            string refEntitySetNameWithEnityID = refEntityIdUrl.Split('/').Last();
                            string refEntityValue = serviceStatus.RootURL.TrimEnd('/') + @"/" + refEntitySetNameWithEnityID;

                            JObject navigationRefSet = new JObject();
                            navigationRefSet.Add(Constants.V4OdataId, refEntityValue);

                            resp                      = WebHelper.UpdateEntity(updateUrl, context.RequestHeaders, navigationRefSet.ToString(), HttpMethod.Put, false);
                            detail                    = new ExtensionRuleResultDetail(this.Name, updateUrl, HttpMethod.Put, string.Empty, resp, string.Empty, refEntityValue.ToString());
                            detail.URI                = updateUrl;
                            detail.ResponsePayload    = resp.ResponsePayload;
                            detail.ResponseHeaders    = resp.ResponseHeaders;
                            detail.HTTPMethod         = "PUT";
                            detail.ResponseStatusCode = resp.StatusCode.ToString();
                        }

                        if (HttpStatusCode.NoContent == resp.StatusCode)
                        {
                            resp   = WebHelper.GetEntity(addedNavigRefUrl);
                            detail = new ExtensionRuleResultDetail(this.Name, addedNavigRefUrl, HttpMethod.Get, string.Empty, resp, string.Empty, reqDataStr);

                            if (HttpStatusCode.OK == resp.StatusCode)
                            {
                                resp = WebHelper.DeleteEntity(addedNavigRefUrl, context.RequestHeaders, false);

                                if (HttpStatusCode.NoContent == resp.StatusCode)
                                {
                                    passed = true;
                                    detail = new ExtensionRuleResultDetail(this.Name, addedNavigRefUrl, HttpMethod.Delete, string.Empty, resp, string.Empty, null);
                                }
                                else
                                {
                                    passed = false;
                                    detail.ErrorMessage = "Cannot remove the reference to the entity.";
                                }
                            }
                            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.";
                }

                // 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(url), serviceStatus.ServiceDocument, details);

            return(passed);
        }
예제 #9
0
        /// <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);
            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;
                NavigationRoughType navigPropRoughType   = NavigationRoughType.None;
                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;
                        navigPropRoughType = np.NavigationRoughType;
                        break;
                    }
                }

                if (!string.IsNullOrEmpty(navigPropRelatedEntityTypeKeyName) && !string.IsNullOrEmpty(navigPropRelatedEntitySetUrl))
                {
                    string entitySetUrl = et.EntitySetName.MapEntitySetNameToEntitySetURL();
                    string url          = serviceStatus.RootURL.TrimEnd('/') + @"/" + entitySetUrl;
                    var    resp         = WebHelper.Get(new Uri(url), Constants.AcceptHeaderJson, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, serviceStatus.DefaultHeaders);
                    detail1 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, StringHelper.MergeHeaders(Constants.AcceptHeaderJson, serviceStatus.DefaultHeaders), resp);

                    if (resp.StatusCode == HttpStatusCode.OK)
                    {
                        JObject feed;
                        resp.ResponsePayload.TryToJObject(out feed);
                        var         entries         = JsonParserHelper.GetEntries(feed);
                        DataFactory factory         = DataFactory.Instance();
                        var         additionalInfos = new List <AdditionalInfo>();
                        var         reqData         = factory.ConstructInsertedEntityData(et.EntitySetName, et.EntityTypeShortName, null, out additionalInfos);
                        string      reqDataStr      = reqData.ToString();
                        resp    = WebHelper.CreateEntity(url, reqDataStr);
                        detail2 = 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('/') + @"/" + navigPropRelatedEntitySetUrl;
                            resp    = WebHelper.Get(new Uri(url), Constants.V4AcceptHeaderJsonFullMetadata, RuleEngineSetting.Instance().DefaultMaximumPayloadSize, serviceStatus.DefaultHeaders);
                            detail3 = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Get, StringHelper.MergeHeaders(Constants.V4AcceptHeaderJsonFullMetadata, serviceStatus.DefaultHeaders), resp);
                            if (resp.StatusCode == HttpStatusCode.OK)
                            {
                                resp.ResponsePayload.TryToJObject(out feed);
                                var entities = JsonParserHelper.GetEntries(feed);
                                if (null != entities && entities.Any())
                                {
                                    string odataID = entities.First[Constants.V4OdataId] != null ? entities.First[Constants.V4OdataId].Value <string>() : string.Empty;

                                    reqDataStr = @"{""" + Constants.V4OdataId + @""" : """ + odataID + @"""}";
                                    url        = string.Format("{0}/{1}/$ref", entityId.TrimEnd('/'), navigPropName.TrimEnd('/'));
                                    resp       = WebHelper.CreateEntity(url, reqDataStr);
                                    detail4    = new ExtensionRuleResultDetail(this.Name, url, HttpMethod.Post, string.Empty, resp, string.Empty, reqDataStr);

                                    if (resp.StatusCode == HttpStatusCode.NoContent)
                                    {
                                        string deleteUrl = url;

                                        if (navigPropRoughType == NavigationRoughType.CollectionValued)
                                        {
                                            deleteUrl = string.Format("{0}/{1}/$entity?$id={2}", entityId.TrimEnd('/'), navigPropName.TrimEnd('/'), entities[0][Constants.V4OdataId].ToString());
                                        }

                                        resp    = WebHelper.DeleteEntity(deleteUrl);
                                        detail5 = new ExtensionRuleResultDetail(this.Name, deleteUrl, HttpMethod.Delete, string.Empty, resp);

                                        if (null != resp && HttpStatusCode.NoContent == resp.StatusCode)
                                        {
                                            passed = true;
                                        }
                                        else
                                        {
                                            passed = false;
                                            detail5.ErrorMessage = "Delete the above reference failed.";
                                        }
                                    }
                                    else
                                    {
                                        passed = false;
                                        detail4.ErrorMessage = "Created navigation failed.";
                                    }
                                }
                            }
                            else
                            {
                                passed = false;
                                detail3.ErrorMessage = "Can not get the created entity from above URI.";
                            }

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

                        break;
                    }
                }
            }

            var details = new List <ExtensionRuleResultDetail>()
            {
                detail1, detail2, detail3, detail4, detail5
            }.RemoveNullableDetails();

            info = new ExtensionRuleViolationInfo(new Uri(serviceStatus.RootURL), serviceStatus.ServiceDocument, details);

            return(passed);
        }
예제 #10
0
        /// <summary>
        /// Get the names of appropriate navigation properties from metadata.
        /// </summary>
        /// <param name="entityTypeShortName">The entity type short name.</param>
        /// <param name="metadataDoc">The metadata document.</param>
        /// <param name="type">The navigation property rough type.</param>
        /// <returns>Returns the list of navigation property names.</returns>
        public static List<string> GetAppropriateNavigationPropertyNames(string entityTypeShortName, string metadataDoc, NavigationRoughType type)
        {
            if (string.IsNullOrEmpty(entityTypeShortName) || string.IsNullOrEmpty(metadataDoc))
            {
                return null;
            }

            List<string> result = new List<string>();
            string xpath = string.Format("//*[local-name()='EntityType' and @Name='{0}']/*[local-name()='NavigationProperty']", entityTypeShortName);
            XElement metadata = XElement.Parse(metadataDoc);
            var navigProps = metadata.XPathSelectElements(xpath, ODataNamespaceManager.Instance);

            if (null == navigProps || !navigProps.Any())
            {
                return null;
            }

            foreach (var np in navigProps)
            {
                if (null == np.Attribute("Name") || null == np.Attribute("Type"))
                {
                    break;
                }

                if (NavigationRoughType.None == type)
                {
                    result.Add(np.GetAttributeValue("Name"));
                }
                else if (NavigationRoughType.SingleValued == type)
                {
                    if (!np.GetAttributeValue("Type").StartsWith("Collection("))
                    {
                        result.Add(np.GetAttributeValue("Name"));
                    }
                }
                else
                {
                    if (np.GetAttributeValue("Type").StartsWith("Collection("))
                    {
                        result.Add(np.GetAttributeValue("Name"));
                    }
                }
            }

            return result;
        }
예제 #11
0
        /// <summary>
        /// Judge whether the entity has specified rough type navigation type property.
        /// </summary>
        /// <param name="metadata">The string of metadata document.</param>
        /// <param name="entityTypeShortName">The short name of entity type.</param>
        /// <param name="type">The rough type of navigation type.</param>
        /// <param name="context">The service context.</param>
        /// <param name="collectionPropNames">Output the list of navigation properties' names.</param>
        /// <returns> True, if the entity has the navigation type property; false, otherwise. </returns>
        public static bool HasEntityNavigationProp(string metadata, string entityTypeShortName, NavigationRoughType type, ServiceContext context, out List<string> navigationPropNames)
        {
            bool hasBaseType = true;
            navigationPropNames = new List<string>();

            while (hasBaseType)
            {
                string typeString = string.Empty;

                switch (type)
                {
                    case NavigationRoughType.CollectionValued:
                        typeString = @"and contains(@Type, 'Collection(')";
                        break;
                    case NavigationRoughType.SingleValued:
                        typeString = @"and not contains(@Type, 'Collection(')";
                        break;
                    default:
                        typeString = string.Empty;
                        break;
                }

                string xpath1 = string.Format(@"//*[local-name()='EntityType' and @Name='{0}']/*[local-name()='NavigationProperty'", entityTypeShortName) + typeString + "]";
                XElement md = XElement.Parse(metadata);
                IEnumerable<XElement> navigationProps = md.XPathSelectElements(xpath1, ODataNamespaceManager.Instance);

                if (navigationProps != null)
                {
                    foreach (XElement prop in navigationProps)
                    {
                        navigationPropNames.Add(prop.Attribute("Name").Value);
                    }
                }

                xpath1 = string.Format(@"//*[local-name()='EntityType' and @Name='{0}']", entityTypeShortName);
                XElement entity = md.XPathSelectElement(xpath1, ODataNamespaceManager.Instance);

                if (null != entity.Attribute("BaseType") && !string.IsNullOrEmpty(entity.Attribute("BaseType").Value))
                {
                    string baseEntityQualifiedName = entity.GetAttributeValue("BaseType");
                    entity = GetTypeDefinitionEleInScope("EntityType", baseEntityQualifiedName, context);
                    entityTypeShortName = entity.Attribute("Name").Value;
                }
                else
                {
                    hasBaseType = false;
                }
            }

            return navigationPropNames != null && navigationPropNames.Any();
        }
예제 #12
0
        /// <summary>
        /// Gets all entity types which were satisfied specified conditions from metadata document. 
        /// </summary>
        /// <param name="metadataDoc">The metadata document.</param>
        /// <param name="entityTypePredicate">Assert whether an entity-type matches specified conditions.</param>
        /// <param name="containedKeyPropSum">The sum of the key properties in current entity-type.</param>
        /// <param name="containedKeyPropTypes">The contained key property types.</param>
        /// <param name="containedNorPropTypes">The contained normal property types.</param>
        /// <param name="containedNavigRoughType">The contained navigation properties' rough-type at least one was satisfied the input value.</param>
        /// <returns></returns>
        public static IEnumerable<EntityTypeElement> GetEntityTypes(
            string metadataDoc,
            uint? containedKeyPropSum = 1,
            IEnumerable<string> containedKeyPropTypes = null,
            IEnumerable<string> containedNorPropTypes = null,
            NavigationRoughType containedNavigRoughType = NavigationRoughType.None)
        {
            if (string.IsNullOrEmpty(metadataDoc))
            {
                return null;
            }

            List<EntityTypeElement> result = new List<EntityTypeElement>();
            XElement metadata = XElement.Parse(metadataDoc);
            string xpath = @"//*[local-name()='Schema']/*[local-name()='EntityType']";
            var elements = metadata.XPathSelectElements(xpath, ODataNamespaceManager.Instance);

            foreach (var ele in elements)
            {
                EntityTypeElement entityType = EntityTypeElement.Parse(ele);

                if (PredicateHelper.EntityTypeAnyPropertiesMeetsSpecifiedConditions(entityType, containedKeyPropSum, containedKeyPropTypes, containedNorPropTypes, containedNavigRoughType))
                {
                    result.Add(entityType);
                }
            }

            return result;
        }