Esempio n. 1
0
        /// <summary>Creates new root node for the projection tree.</summary>
        /// <param name="resourceSetWrapper">The resource set of the root level of the query.</param>
        /// <param name="orderingInfo">The ordering info for this node. null means no ordering to be applied.</param>
        /// <param name="filter">The filter for this node. null means no filter to be applied.</param>
        /// <param name="skipCount">Number of results to skip. null means no results to be skipped.</param>
        /// <param name="takeCount">Maximum number of results to return. null means return all available results.</param>
        /// <param name="maxResultsExpected">Maximum number of expected results. Hint that the provider should return
        /// at least maxResultsExpected + 1 results (if available).</param>
        /// <param name="expandPaths">The list of expanded paths.</param>
        /// <param name="baseResourceType">The resource type for all entities in this query.</param>
        /// <param name="selectExpandClause">The select expand clause for the current node from the URI Parser.</param>
        internal RootProjectionNode(
            ResourceSetWrapper resourceSetWrapper,
            OrderingInfo orderingInfo,
            Expression filter,
            int? skipCount,
            int? takeCount,
            int? maxResultsExpected,
            List<ExpandSegmentCollection> expandPaths,
            ResourceType baseResourceType,
            SelectExpandClause selectExpandClause)
            : base(
                String.Empty,
                null,
                null,
                resourceSetWrapper,
                orderingInfo,
                filter,
                skipCount,
                takeCount,
                maxResultsExpected,
                selectExpandClause)
        {
            Debug.Assert(baseResourceType != null, "baseResourceType != null");

            this.expandPaths = expandPaths;
            this.baseResourceType = baseResourceType;
        }
        public void Init()
        {
            this.baseType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, null, "Fake.NS", "BaseType", false) {CanReflectOnInstanceType = false};
            this.baseType.AddProperty(new ResourceProperty("Id", ResourcePropertyKind.Key | ResourcePropertyKind.Primitive, ResourceType.GetPrimitiveResourceType(typeof(int))) { CanReflectOnInstanceTypeProperty = false });
            this.baseType.SetReadOnly();
            
            this.entityType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, this.baseType, "Fake.NS", "Type", false) {CanReflectOnInstanceType = false};
            this.entityType.SetReadOnly();

            this.derivedType = new ResourceType(typeof(object), ResourceTypeKind.EntityType, this.entityType, "Fake.NS", "DerivedType", false) { CanReflectOnInstanceType = false };
            this.derivedType.SetReadOnly();

            var resourceSet = new ResourceSet("Set", this.entityType);
            resourceSet.SetReadOnly();
            this.resourceSetWrapper = ResourceSetWrapper.CreateForTests(resourceSet);

            this.action = new ServiceAction("Fake", ResourceType.GetPrimitiveResourceType(typeof(int)), OperationParameterBindingKind.Sometimes, new[] {new ServiceActionParameter("p1", this.entityType)}, null);
            this.action.SetReadOnly();
            this.actionWrapper = new OperationWrapper(action);

            this.derivedAction = new ServiceAction("Fake", ResourceType.GetPrimitiveResourceType(typeof(int)), OperationParameterBindingKind.Sometimes, new[] { new ServiceActionParameter("p1", this.derivedType) }, null);
            this.derivedAction.SetReadOnly();
            this.derivedActionWrapper = new OperationWrapper(derivedAction);

            this.testSubject = new SelectedOperationsCache();
        }
Esempio n. 3
0
        /// <summary>
        /// Gets the target set from the binding set and path expression.
        /// </summary>
        /// <param name="provider">Provider instance to resolve the association set.</param>
        /// <param name="bindingSet">Binding resource set.</param>
        /// <returns>Returns the target resource set for the path expression.</returns>
        internal ResourceSetWrapper GetTargetSet(DataServiceProviderWrapper provider, ResourceSetWrapper bindingSet)
        {
            Debug.Assert(provider != null, "provider != null");
            Debug.Assert(bindingSet != null, "sourceSet != null");
            Debug.Assert(this.pathSegments != null && this.pathSegments.Length > 0, "InitializePathSegments() must be called before this.");
            Debug.Assert(bindingSet.ResourceType.IsAssignableFrom(this.pathSegments[0].SourceType), "bindingSet.ResourceType.IsAssignableFrom(this.pathSegments[0].SourceType)");

            ResourceSetWrapper resultSet = bindingSet;

            for (int idx = 0; resultSet != null && idx < this.pathSegments.Length; idx++)
            {
                PathSegment segment = this.pathSegments[idx];
                if (segment.Property != null)
                {
                    resultSet = provider.GetResourceSet(resultSet, segment.SourceType, segment.Property);
                }
#if DEBUG
                else
                {
                    Debug.Assert(idx == 0, "Path cannot end with type identifier.");
                }
#endif
            }

            return(resultSet);
        }
Esempio n. 4
0
        /// <summary>Fires the notification for a single action.</summary>
        /// <param name="service">Service on which methods should be invoked.</param>
        /// <param name="target">Object to be tracked.</param>
        /// <param name="container">Container in which object is changed.</param>
        /// <param name="action">Action affecting target.</param>
        internal static void FireNotification(IDataService service, object target, ResourceSetWrapper container, UpdateOperations action)
        {
            Debug.Assert(service != null, "service != null");
            AssertActionValues(target, container);

            MethodInfo[] methods = container.ChangeInterceptors;
            if (methods != null)
            {
                object[] parameters = new object[2];
                parameters[0] = target;
                parameters[1] = action;
                for (int i = 0; i < methods.Length; i++)
                {
                    try
                    {
                        methods[i].Invoke(service.Instance, parameters);
                    }
                    catch (TargetInvocationException exception)
                    {
                        ErrorHandler.HandleTargetInvocationException(exception);
                        throw;
                    }
                }
            }
        }
Esempio n. 5
0
        /// <summary>Creates new root node for the projection tree.</summary>
        /// <param name="resourceSetWrapper">The resource set of the root level of the query.</param>
        /// <param name="orderingInfo">The ordering info for this node. null means no ordering to be applied.</param>
        /// <param name="filter">The filter for this node. null means no filter to be applied.</param>
        /// <param name="skipCount">Number of results to skip. null means no results to be skipped.</param>
        /// <param name="takeCount">Maximum number of results to return. null means return all available results.</param>
        /// <param name="maxResultsExpected">Maximum number of expected results. Hint that the provider should return
        /// at least maxResultsExpected + 1 results (if available).</param>
        /// <param name="expandPaths">The list of expanded paths.</param>
        /// <param name="baseResourceType">The resource type for all entities in this query.</param>
        /// <param name="selectExpandClause">The select expand clause for the current node from the URI Parser.</param>
        internal RootProjectionNode(
            ResourceSetWrapper resourceSetWrapper,
            OrderingInfo orderingInfo,
            Expression filter,
            int?skipCount,
            int?takeCount,
            int?maxResultsExpected,
            List <ExpandSegmentCollection> expandPaths,
            ResourceType baseResourceType,
            SelectExpandClause selectExpandClause)
            : base(
                String.Empty,
                null,
                null,
                resourceSetWrapper,
                orderingInfo,
                filter,
                skipCount,
                takeCount,
                maxResultsExpected,
                selectExpandClause)
        {
            Debug.Assert(baseResourceType != null, "baseResourceType != null");

            this.expandPaths      = expandPaths;
            this.baseResourceType = baseResourceType;
        }
Esempio n. 6
0
        /// <summary>Creates new instance of node representing expanded navigation property.</summary>
        /// <param name="propertyName">The name of the property to project and expand.</param>
        /// <param name="property">The <see cref="ResourceProperty"/> for this property. Can only be null for the root node.</param>
        /// <param name="targetResourceType">Target resource type on which the expansion needs to happen.</param>
        /// <param name="resourceSetWrapper">The resource set to which the expansion leads.</param>
        /// <param name="orderingInfo">The ordering info for this node. null means no ordering to be applied.</param>
        /// <param name="filter">The filter for this node. null means no filter to be applied.</param>
        /// <param name="skipCount">Number of results to skip. null means no results to be skipped.</param>
        /// <param name="takeCount">Maximum number of results to return. null means return all available results.</param>
        /// <param name="maxResultsExpected">Maximum number of expected results. Hint that the provider should return
        /// at least maxResultsExpected + 1 results (if available).</param>
        /// <param name="selectExpandClause">The select expand clause for the current node from the URI Parser.</param>
        internal ExpandedProjectionNode(
            string propertyName,
            ResourceProperty property,
            ResourceType targetResourceType,
            ResourceSetWrapper resourceSetWrapper,
            OrderingInfo orderingInfo,
            Expression filter,
            int?skipCount,
            int?takeCount,
            int?maxResultsExpected,
            SelectExpandClause selectExpandClause)
            : base(propertyName, property, targetResourceType)
        {
            Debug.Assert(resourceSetWrapper != null, "resourceSetWrapper != null");
            Debug.Assert(property != null || (propertyName.Length == 0 && targetResourceType == null), "We don't support open navigation properties.");
            Debug.Assert(property == null || targetResourceType.TryResolvePropertyName(property.Name) != null, "Property must exist on the target resource type");
            Debug.Assert(selectExpandClause != null, "selectExpandClause != null");

            this.resourceSetWrapper = resourceSetWrapper;
            this.orderingInfo       = orderingInfo;
            this.filter             = filter;
            this.skipCount          = skipCount;
            this.takeCount          = takeCount;
            this.maxResultsExpected = maxResultsExpected;
            this.nodes = new List <ProjectionNode>();
            this.hasExpandedPropertyOnDerivedType = false;
            this.selectExpandClause = selectExpandClause;
        }
Esempio n. 7
0
        /// <summary>
        /// Gets the result set for the operation.
        /// </summary>
        /// <param name="provider">Provider instance to resolve the path expression.</param>
        /// <param name="bindingSet">Binding resource set.</param>
        /// <returns>Returns the result resource set for the operation.</returns>
        internal ResourceSetWrapper GetResultSet(DataServiceProviderWrapper provider, ResourceSetWrapper bindingSet)
        {
#if DEBUG
            Debug.Assert(this.isReadOnly, "Wrapper class has not been initialized yet.");
#endif
            if (this.resourceSet != null)
            {
                Debug.Assert(this.resourceSet.ResourceSet == this.operation.ResourceSet, "this.resourceSet.ResourceSet == this.serviceOperation.ResourceSet");
                Debug.Assert(this.ResultSetPathExpression == null, "this.ResultSetPathExpression == null");
                return(this.resourceSet);
            }

            if (this.ResultSetPathExpression != null)
            {
                Debug.Assert(provider != null, "provider != null");
                if (bindingSet == null)
                {
                    throw new InvalidOperationException(Strings.OperationWrapper_PathExpressionRequiresBindingSet(this.Name));
                }

                ResourceSetWrapper resultSet = this.ResultSetPathExpression.GetTargetSet(provider, bindingSet);
                if (resultSet == null)
                {
                    throw new InvalidOperationException(Strings.OperationWrapper_TargetSetFromPathExpressionNotNotVisible(this.Name, this.ResultSetPathExpression.PathExpression, bindingSet.Name));
                }

                return(resultSet);
            }

            return(null);
        }
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="model">The edm model this instance belongs to.</param>
        /// <param name="entityContainer">Entity container instance that this set belongs to.</param>
        /// <param name="resourceSet">ResourceSet that this entity set represents.</param>
        internal MetadataProviderEdmEntitySet(MetadataProviderEdmModel model, MetadataProviderEdmEntityContainer entityContainer, ResourceSetWrapper resourceSet)
        {
            Debug.Assert(model != null, "model != null");
            Debug.Assert(entityContainer != null, "entityContainer != null");
            Debug.Assert(resourceSet != null, "resourceSet != null");

            this.model           = model;
            this.entityContainer = entityContainer;
            this.resourceSet     = resourceSet;
        }
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="model">The edm model this instance belongs to.</param>
        /// <param name="entityContainer">Entity container instance that this set belongs to.</param>
        /// <param name="resourceSet">ResourceSet that this entity set represents.</param>
        internal MetadataProviderEdmEntitySet(MetadataProviderEdmModel model, MetadataProviderEdmEntityContainer entityContainer, ResourceSetWrapper resourceSet)
        {
            Debug.Assert(model != null, "model != null");
            Debug.Assert(entityContainer != null, "entityContainer != null");
            Debug.Assert(resourceSet != null, "resourceSet != null");

            this.model = model;
            this.entityContainer = entityContainer;
            this.resourceSet = resourceSet;
        }
        /// <summary>
        /// Adds an entity set backed by the <paramref name="resourceSet"/> to the entity container.
        /// </summary>
        /// <param name="entitySetName">The name of the entity set.</param>
        /// <param name="resourceSet">The resource set backing the entity set to be created.</param>
        /// <returns>an instance of IEdmEntitySet that just got added.</returns>
        /// <remarks>
        /// This method will also create the association sets and associations for the entity set.
        /// Materialization state: EntityContainers required. No change in materialization state.
        /// </remarks>
        internal IEdmEntitySet AddEntitySet(string entitySetName, ResourceSetWrapper resourceSet)
        {
            Debug.Assert(!string.IsNullOrEmpty(entitySetName), "!string.IsNullOrEmpty(entitySetName)");
            Debug.Assert(resourceSet != null, "resourceSet != null");

            IEdmEntitySet entitySet = new MetadataProviderEdmEntitySet(this.model, this, resourceSet);

            MetadataProviderUtils.ConvertCustomAnnotations(this.model, resourceSet.CustomAnnotations, entitySet);
            this.entitySetCache.Add(entitySetName, entitySet);
            return(entitySet);
        }
Esempio n. 11
0
        /// <summary>
        /// Creates the wrapper from the given resource set for use in unit tests.
        /// </summary>
        /// <param name="resourceSet">resource set instance whose wrapper needs to get created.</param>
        /// <param name="rights">Optional rights for the set. Defaults to None.</param>
        /// <returns>Wrapper for the given resource set.</returns>
        internal static ResourceSetWrapper CreateForTests(ResourceSet resourceSet, EntitySetRights rights = EntitySetRights.None)
        {
            var resourceSetWrapper = new ResourceSetWrapper(resourceSet)
            {
                rights = rights,
#if DEBUG
                isReadOnly = true
#endif
            };

            return(resourceSetWrapper);
        }
Esempio n. 12
0
        /// <summary>
        /// Creates the wrapper from the given resource set. This method returns null, if the given resource set is not visible.
        /// It also checks for the resource set metadata to make sure that the MPV in the configuration is set correctly
        /// </summary>
        /// <param name="resourceSet">resource set instance whose wrapper needs to get created.</param>
        /// <param name="provider">DataServiceProviderWrapper instance.</param>
        /// <param name="resourceTypeValidator">resource type validator.</param>
        /// <returns>Wrapper for the given resource set, if the resource set/resource type metadata is valid and adheres to the protocol version in the server.</returns>
        internal static ResourceSetWrapper CreateResourceSetWrapper(ResourceSet resourceSet, DataServiceProviderWrapper provider, Func <ResourceType, ResourceType> resourceTypeValidator)
        {
            ResourceSetWrapper resourceSetWrapper = new ResourceSetWrapper(resourceSet);

            resourceSetWrapper.ApplyConfiguration(provider.Configuration, provider.StaticConfiguration);
            if (!resourceSetWrapper.IsVisible)
            {
                return(null);
            }

            // Only validate the resource type if the set is visible.
            resourceSetWrapper.resourceType = resourceTypeValidator(resourceSet.ResourceType);
            return(resourceSetWrapper);
        }
Esempio n. 13
0
        /// <summary>
        /// Retrieve the related end for the given resource set, type and property.
        /// </summary>
        /// <param name="resourceSet">resource set for the source end</param>
        /// <param name="resourceType">resource type for the source end</param>
        /// <param name="resourceProperty">resource property for the source end</param>
        /// <returns>Related resource association set end for the given parameters</returns>
        internal ResourceAssociationSetEnd GetRelatedResourceAssociationSetEnd(ResourceSetWrapper resourceSet, ResourceType resourceType, ResourceProperty resourceProperty)
        {
            Debug.Assert(resourceSet != null, "resourceSet != null");
            Debug.Assert(resourceType != null, "resourceType != null");

            ResourceAssociationSetEnd thisEnd = this.GetResourceAssociationSetEnd(resourceSet, resourceType, resourceProperty);

            if (thisEnd != null)
            {
                return(thisEnd == this.End1 ? this.End2 : this.End1);
            }

            return(null);
        }
Esempio n. 14
0
 /// <summary>Initializes a new <see cref="ExpandSegment"/> instance.</summary>
 /// <param name="name">Segment name.</param>
 /// <param name="filter">Filter expression for segment, possibly null.</param>
 /// <param name="maxResultsExpected">
 /// Expand providers may choose to return at most MaxResultsExpected + 1 elements to allow the
 /// data service to detect a failure to meet this constraint.
 /// </param>
 /// <param name="container">Container to which the segment belongs; possibly null.</param>
 /// <param name="targetResourceType">Target resource type on which the expansion needs to happen.</param>
 /// <param name="expandedProperty">Property expanded by this expand segment</param>
 /// <param name="orderingInfo">Collection of ordering information for this segment, used for paging</param>
 internal ExpandSegment(
     string name, 
     Expression filter, 
     int maxResultsExpected, 
     ResourceSetWrapper container,
     ResourceType targetResourceType,
     ResourceProperty expandedProperty, 
     OrderingInfo orderingInfo)
 {
     WebUtil.CheckArgumentNull(name, "name");
     CheckFilterType(filter);
     this.name = name;
     this.filter = filter;
     this.container = container;
     this.maxResultsExpected = maxResultsExpected;
     this.expandedProperty = expandedProperty;
     this.orderingInfo = orderingInfo;
     this.targetResourceType = targetResourceType;
 }
Esempio n. 15
0
        /// <summary>
        /// Retrieve the end for the given resource set, type and property.
        /// </summary>
        /// <param name="resourceSet">resource set for the end</param>
        /// <param name="resourceType">resource type for the end</param>
        /// <param name="resourceProperty">resource property for the end</param>
        /// <returns>Resource association set end for the given parameters</returns>
        internal ResourceAssociationSetEnd GetResourceAssociationSetEnd(ResourceSetWrapper resourceSet, ResourceType resourceType, ResourceProperty resourceProperty)
        {
            Debug.Assert(resourceSet != null, "resourceSet != null");
            Debug.Assert(resourceType != null, "resourceType != null");

            foreach (ResourceAssociationSetEnd end in new[] { this.end1, this.end2 })
            {
                if (end.ResourceSet.Name == resourceSet.Name && end.ResourceType.IsAssignableFrom(resourceType))
                {
                    if ((end.ResourceProperty == null && resourceProperty == null) ||
                        (end.ResourceProperty != null && resourceProperty != null && end.ResourceProperty.Name == resourceProperty.Name))
                    {
                        return(end);
                    }
                }
            }

            return(null);
        }
Esempio n. 16
0
        /// <summary>
        /// Creates a new instance of <see cref="EntityToSerialize"/>.
        /// </summary>
        /// <param name="entity">The entity itself.</param>
        /// <param name="resourceType">The type of the entity.</param>
        /// <param name="resourceSetWrapper">The resource set the entity belongs to.</param>
        /// <param name="provider">The wrapper for the current service provider.</param>
        /// <param name="absoluteServiceUri">The absolute service URI.</param>
        /// <returns>The new instance of <see cref="EntityToSerialize"/></returns>
        internal static EntityToSerialize Create(object entity, ResourceType resourceType, ResourceSetWrapper resourceSetWrapper, DataServiceProviderWrapper provider, Uri absoluteServiceUri)
        {
            Debug.Assert(provider != null, "provider != null");
            Debug.Assert(provider.DataService != null, "provider.DataService != null");
            Debug.Assert(provider.DataService.Configuration != null, "provider.DataService.Configuration != null");

            KeySerializer keySerializer = KeySerializer.Create(UrlConvention.Create(provider.DataService));
            Func<ResourceProperty, object> getPropertyValue = p =>
            {
                object keyValue = WebUtil.GetPropertyValue(provider, entity, resourceType, p, null);
                if (keyValue == null)
                {
                    throw new InvalidOperationException(Service.Strings.Serializer_NullKeysAreNotSupported(p.Name));
                }

                return keyValue;
            };

            bool includeTypeSegment = resourceSetWrapper.ResourceType != resourceType;

            return Create(entity, resourceType, resourceSetWrapper.Name, includeTypeSegment, getPropertyValue, keySerializer, absoluteServiceUri);
        }
Esempio n. 17
0
        /// <summary>
        /// Apply the given configuration to the resource set.
        /// </summary>
        /// <param name="configuration">data service configuration instance.</param>
        /// <param name="provider">data service provider wrapper instance for accessibility validation.</param>
        public void ApplyConfiguration(DataServiceConfiguration configuration, DataServiceProviderWrapper provider)
        {
#if DEBUG
            Debug.Assert(!this.isReadOnly, "Can only apply the configuration once.");
#endif
            if (this.Kind == OperationKind.ServiceOperation)
            {
                this.serviceOperationRights = configuration.GetServiceOperationRights(this.ServiceOperation);
            }
            else
            {
                Debug.Assert(this.Kind == OperationKind.Action, "this.Kind == OperationKind.Action");
                this.serviceActionRights = configuration.GetServiceActionRights(this.ServiceAction);
            }

            if ((this.Kind == OperationKind.ServiceOperation && (this.serviceOperationRights & ~ServiceOperationRights.OverrideEntitySetRights) != ServiceOperationRights.None) ||
                (this.Kind == OperationKind.Action && this.serviceActionRights != Service.ServiceActionRights.None))
            {
                if (this.operation.ResourceSet != null)
                {
                    // If the result type is an entity type, we need to make sure its entity set is visible.
                    // If the entity set is hidden, we need to make sure that we throw an exception.
                    this.resourceSet = provider.TryResolveResourceSet(this.operation.ResourceSet.Name);
                    if (this.resourceSet == null)
                    {
                        throw new InvalidOperationException(Strings.OperationWrapper_OperationResourceSetNotVisible(this.Name, this.operation.ResourceSet.Name));
                    }
                }
                else if (this.ResultSetPathExpression != null)
                {
                    this.ResultSetPathExpression.InitializePathSegments(provider);
                }
            }
#if DEBUG
            this.isReadOnly = true;
#endif
        }
Esempio n. 18
0
        /// <summary>Updates the request and response versions based on response format and the target resource set</summary>
        /// <param name="resourceSet">resourceSet to check for friendly feeds presence</param>
        /// <param name="service">data service instance</param>
        internal void UpdateVersion(ResourceSetWrapper resourceSet, IDataService service)
        {
            Debug.Assert(service != null, "service is null");
            Debug.Assert(service.Provider != null, "provider != null");

            AstoriaRequestMessage host = service.OperationContext.RequestMessage;
            if (host.HttpVerb.IsQuery() ||
                (host.HttpVerb == HttpVerbs.POST && this.TargetSource == RequestTargetSource.ServiceOperation))
            {
                // Update the response DSV for GET according to the features used by the resource set being requested
                //
                // Note the response DSV is payload specific and since for GET we won't know what DSV the instances to be
                // serialized will require until serialization time which happens after the headers are written, 
                // the best we can do is to determin this at the set level.
                //
                // For CUD operations we'll raise the version based on the actual instances at deserialization time.
                if (this.TargetKind == RequestTargetKind.Resource)
                {
                    Debug.Assert(resourceSet != null, "Must have valid resource set");

                    if (!this.LinkUri)
                    {
                        this.InitializeVersion(service);

                        Version version = resourceSet.MinimumResponsePayloadVersion(service);
                        this.VerifyAndRaiseResponseVersion(version, service);
                    }
                }
                else if (this.TargetResourceType != null &&
                    this.CountOption != RequestQueryCountOption.CountSegment &&
                    this.TargetKind != RequestTargetKind.MediaResource)
                {
                    // Except $count requests and named stream requests, we need to bump up the version
                    // based on the target resource type.
                    // For named streams, the response version is always 1.0 since we supported media streams in V1.
                    // For $count requests, the response version is always 1.0 since the result is an Int64
                    this.VerifyAndRaiseResponseVersion(this.TargetResourceType.MetadataVersion, service);
                }
                else if (this.TargetKind == RequestTargetKind.OpenProperty)
                {
                    this.InitializeVersion(service);

                    // When we encounter open properties, raise the response version to the highest version possible,
                    // since we do not know what the metadata is going to be.
                    this.VerifyAndRaiseResponseVersion(this.effectiveMaxResponseVersion, service);
                }
            }
        }
Esempio n. 19
0
        /// <summary>
        /// Returns the last segment info whose target request kind is resource
        /// </summary>
        /// <param name="description">description about the target request</param>
        /// <param name="service">data service type to which the request was made</param>
        /// <param name="allowCrossReferencing">whether cross-referencing is allowed for the resource in question.</param>
        /// <param name="entityResource">entity resource which is getting modified.</param>
        /// <param name="entityContainer">entity container of the entity which is getting modified.</param>
        /// <param name="checkETag">whether to check the etag for the entity resource that is getting modified.</param>
        /// <returns>Returns the object that needs to get modified</returns>
        internal static object GetResourceToModify(
            RequestDescription description,
            IDataService service,
            bool allowCrossReferencing,
            out object entityResource,
            out ResourceSetWrapper entityContainer,
            bool checkETag)
        {
            // Set the index of the modifying resource
            int modifyingResourceIndex;
            if (
                description.TargetKind == RequestTargetKind.OpenPropertyValue ||
                description.TargetKind == RequestTargetKind.PrimitiveValue)
            {
                modifyingResourceIndex = description.SegmentInfos.Count - 3;
            }
            else
            {
                modifyingResourceIndex = description.SegmentInfos.Count - 2;
            }

            int entityResourceIndex;
            entityResource = Deserializer.GetEntityResourceToModify(
                description,
                service,
                allowCrossReferencing,
                out entityContainer,
                out entityResourceIndex);

            // now walk from the entity resource to the resource to modify.
            // for open types, as you walk, if the intermediate resource is an entity,
            // update the entityResource accordingly.
            object resourceToModify = entityResource;
            for (int i = entityResourceIndex + 1; i <= modifyingResourceIndex; i++)
            {
                // If the segment is a type identifier segment, skip the segment. There is no need to issue one more query
                // to the provider.
                if (description.SegmentInfos[i].IsTypeIdentifierSegment)
                {
                    continue;
                }

#if DEBUG
                SegmentInfo segmentInfo = description.SegmentInfos[i];
                Debug.Assert(segmentInfo.TargetKind != RequestTargetKind.Resource, "segmentInfo.TargetKind != RequestTargetKind.Resource");
#endif
                resourceToModify = service.Updatable.GetValue(resourceToModify, description.SegmentInfos[i].Identifier);
            }

            // If checkETag is true, then we need to check the etag for the resource
            // Note that MediaResource has a separate etag, we don't need to check the MLE etag if the target kind is MediaResource
            if (checkETag && !WebUtil.IsCrossReferencedSegment(description.SegmentInfos[modifyingResourceIndex], service) && description.TargetKind != RequestTargetKind.MediaResource)
            {
                service.Updatable.SetETagValues(entityResource, entityContainer);
            }

            return resourceToModify;
        }
Esempio n. 20
0
 /// <summary>
 /// Returns the entity that need to get modified
 /// </summary>
 /// <param name="description">description about the target request</param>
 /// <param name="service">data service type to which the request was made</param>
 /// <param name="allowCrossReferencing">whether cross-referencing is allowed for the resource in question.</param>
 /// <param name="entityContainer">entity container of the entity which is getting modified.</param>
 /// <returns>Returns the entity that needs to get modified</returns>
 internal static object GetEntityResourceToModify(
     RequestDescription description,
     IDataService service,
     bool allowCrossReferencing,
     out ResourceSetWrapper entityContainer)
 {
     int entityResourceIndex;
     return Deserializer.GetEntityResourceToModify(
         description,
         service,
         allowCrossReferencing,
         out entityContainer,
         out entityResourceIndex);
 }
Esempio n. 21
0
 private static void AssertActionValues(object target, ResourceSetWrapper container)
 {
     Debug.Assert(target != null, "target != null");
     Debug.Assert(container != null, "container != null");
 }
        /// <summary>
        /// Gets a string representation of allowed methods on the container (with the specified target cardinality),
        /// suitable for an 'Allow' header.
        /// </summary>
        /// <param name="configuration">configuration object which has the data</param>
        /// <param name="container">Targetted container, possibly null.</param>
        /// <param name="description">Description with target.</param>
        /// <returns>A value for an 'Allow' header; null if <paramref name="container"/> is null.</returns>
        internal static string GetAllowedMethods(DataServiceConfiguration configuration, ResourceSetWrapper container, RequestDescription description)
        {
            if (container == null)
            {
                return null;
            }

            System.Text.StringBuilder result = new System.Text.StringBuilder();
            EntitySetRights rights = configuration.GetResourceSetRights(container.ResourceSet);
            if (description.IsSingleResult)
            {
                AppendRight(rights, EntitySetRights.ReadSingle, XmlConstants.HttpMethodGet, result);
                AppendRight(rights, EntitySetRights.WriteReplace, XmlConstants.HttpMethodPut, result);
                if (description.TargetKind != RequestTargetKind.MediaResource)
                {
                    AppendRight(rights, EntitySetRights.WriteMerge, XmlConstants.HttpMethodPatch, result);
                    AppendRight(rights, EntitySetRights.WriteDelete, XmlConstants.HttpMethodDelete, result);
                }
            }
            else
            {
                AppendRight(rights, EntitySetRights.ReadMultiple, XmlConstants.HttpMethodGet, result);
                AppendRight(rights, EntitySetRights.WriteAppend, XmlConstants.HttpMethodPost, result);
            }

            return result.ToString();
        }
        /// <summary>Checks whether this request has the specified rights.</summary>
        /// <param name="container">Container to check.</param>
        /// <param name="requiredRights">Required rights.</param>
        /// <exception cref="DataServiceException">Thrown if <paramref name="requiredRights"/> aren't available.</exception>
        internal static void CheckResourceRights(ResourceSetWrapper container, EntitySetRights requiredRights)
        {
            Debug.Assert(container != null, "container != null");
            Debug.Assert(requiredRights != EntitySetRights.None, "requiredRights != EntitySetRights.None");

            if ((requiredRights & container.Rights) == 0)
            {
                throw DataServiceException.CreateForbidden();
            }
        }
Esempio n. 24
0
        /// <summary>
        /// Apply the given configuration to the resource set.
        /// </summary>
        /// <param name="configuration">data service configuration instance.</param>
        /// <param name="provider">data service provider wrapper instance for accessibility validation.</param>
        public void ApplyConfiguration(DataServiceConfiguration configuration, DataServiceProviderWrapper provider)
        {
#if DEBUG
            Debug.Assert(!this.isReadOnly, "Can only apply the configuration once.");
#endif
            if (this.Kind == OperationKind.ServiceOperation)
            {
                this.serviceOperationRights = configuration.GetServiceOperationRights(this.ServiceOperation);
            }
            else
            {
                Debug.Assert(this.Kind == OperationKind.Action, "this.Kind == OperationKind.Action");
                this.serviceActionRights = configuration.GetServiceActionRights(this.ServiceAction);
            }

            if ((this.Kind == OperationKind.ServiceOperation && (this.serviceOperationRights & ~ServiceOperationRights.OverrideEntitySetRights) != ServiceOperationRights.None) ||
                (this.Kind == OperationKind.Action && this.serviceActionRights != Service.ServiceActionRights.None))
            {
                if (this.operation.ResourceSet != null)
                {
                    // If the result type is an entity type, we need to make sure its entity set is visible.
                    // If the entity set is hidden, we need to make sure that we throw an exception.
                    this.resourceSet = provider.TryResolveResourceSet(this.operation.ResourceSet.Name);
                    if (this.resourceSet == null)
                    {
                        throw new InvalidOperationException(Strings.OperationWrapper_OperationResourceSetNotVisible(this.Name, this.operation.ResourceSet.Name));
                    }
                }
                else if (this.ResultSetPathExpression != null)
                {
                    this.ResultSetPathExpression.InitializePathSegments(provider);
                }
            }
#if DEBUG
            this.isReadOnly = true;
#endif
        }
Esempio n. 25
0
        /// <summary>Creates a new SegmentInfo for the specified <paramref name="property"/>.</summary>
        /// <param name="property">Property to create segment info for (possibly null).</param>
        /// <param name="propertyName">Name for the property.</param>
        /// <param name="propertySet">Target resource set for the property.</param>
        /// <param name="singleResult">Whether a single result is expected.</param>
        /// <returns>
        /// A new <see cref="SegmentInfo"/> instance that describes the specfied <paramref name="property"/>
        /// as a target, or an open proprty if <paramref name="property"/> is null.
        /// </returns>
        protected static SegmentInfo CreateSegment(ResourceProperty property, string propertyName, ResourceSetWrapper propertySet, bool singleResult)
        {
            SegmentInfo result = new SegmentInfo();
            result.TargetSource = RequestTargetSource.Property;
            result.SingleResult = singleResult;
            result.Identifier = propertyName;
            if (property == null)
            {
                result.TargetKind = RequestTargetKind.OpenProperty;
            }
            else
            {
                result.TargetKind = RequestTargetKind.Resource;
                result.Identifier = propertyName;
                result.ProjectedProperty = property;
                result.TargetResourceType = property.ResourceType;
                result.TargetResourceSet = propertySet;
            }

            return result;
        }
        /// <summary>
        /// Retrieve the end for the given resource set, type and property.
        /// </summary>
        /// <param name="resourceSet">resource set for the end</param>
        /// <param name="resourceType">resource type for the end</param>
        /// <param name="resourceProperty">resource property for the end</param>
        /// <returns>Resource association set end for the given parameters</returns>
        internal ResourceAssociationSetEnd GetResourceAssociationSetEnd(ResourceSetWrapper resourceSet, ResourceType resourceType, ResourceProperty resourceProperty)
        {
            Debug.Assert(resourceSet != null, "resourceSet != null");
            Debug.Assert(resourceType != null, "resourceType != null");

            foreach (ResourceAssociationSetEnd end in new[] { this.end1, this.end2 })
            {
                if (end.ResourceSet.Name == resourceSet.Name && end.ResourceType.IsAssignableFrom(resourceType))
                {
                    if ((end.ResourceProperty == null && resourceProperty == null) ||
                        (end.ResourceProperty != null && resourceProperty != null && end.ResourceProperty.Name == resourceProperty.Name))
                    {
                        return end;
                    }
                }
            }

            return null;
        }
 /// <summary>
 /// Gets the entity set for the specified <paramref name="resourceSet"/>
 /// </summary>
 /// <param name="resourceSet">ResourceSet instance.</param>
 /// <returns>an IEdmEntitySet instance for the given resource set.</returns>
 protected IEdmEntitySet GetEntitySet(ResourceSetWrapper resourceSet)
 {
     return this.Service.Provider.GetMetadataProviderEdmModel().EnsureEntitySet(resourceSet);
 }
Esempio n. 28
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="model">The model this instance belongs to.</param>
        /// <param name="operation">The resource operation underlying this function import.</param>
        /// <param name="namespaceName">The namespace of the operation.</param>
        /// <remarks>This constructor assumes that the entity set for this service operation has already be created.</remarks>
        protected internal MetadataProviderEdmOperation(MetadataProviderEdmModel model, OperationWrapper operation, string namespaceName)
        {
            Debug.Assert(model != null, "model != null");
            Debug.Assert(operation != null, "operation != null");

            this.model            = model;
            this.ServiceOperation = operation;
            this.Namespace        = namespaceName;

            if (operation.Kind == OperationKind.Action)
            {
                this.isBound = this.ServiceOperation.BindingParameter != null;
            }
            else
            {
                Debug.Assert(operation.Kind == OperationKind.ServiceOperation, "serviceOperation.Kind == OperationKind.ServiceOperation");
                Debug.Assert(operation.OperationParameterBindingKind == OperationParameterBindingKind.Never, "operation.OperationParameterBindingKind == OperationParameterBindingKind.Never");
                this.isBound = DefaultIsBindable;
            }

            // EntitySetPath=<path string>
            ResourceSetPathExpression resultSetPathExpression = operation.ResultSetPathExpression;

            this.entitySetPath = resultSetPathExpression == null ? null : resultSetPathExpression.PathExpression;

#if DEBUG
            ResourceType       returnType = operation.ReturnType;
            ResourceSetWrapper resultSet  = operation.ResourceSet;

            Debug.Assert(
                returnType == null || returnType.ResourceTypeKind == ResourceTypeKind.EntityCollection || returnType.ResourceTypeKind == ResourceTypeKind.EntityType || (resultSet == null && resultSetPathExpression == null),
                "resultSet and resultSetPathExpression must be both null when the return type is not an entity type or an entity collection type.");
            Debug.Assert(
                (returnType == null || returnType.ResourceTypeKind != ResourceTypeKind.EntityCollection && returnType.ResourceTypeKind != ResourceTypeKind.EntityType) || (resultSet != null || resultSetPathExpression != null),
                "One of resultSet or resultSetPathExpression must be set when the return type is either an entity type or an entity collection type.");
            Debug.Assert(resultSet == null || resultSetPathExpression == null, "resultSet and resultSetPathExpression cannot be both set.");
#endif

            string mimeType = operation.MimeType;
            if (!string.IsNullOrEmpty(mimeType))
            {
                model.SetMimeType(this, mimeType);
            }

            switch (this.ServiceOperation.OperationParameterBindingKind)
            {
            case OperationParameterBindingKind.Always:
                break;

            default:
                Debug.Assert(
                    this.ServiceOperation.OperationParameterBindingKind == OperationParameterBindingKind.Sometimes ||
                    this.ServiceOperation.OperationParameterBindingKind == OperationParameterBindingKind.Never,
                    "this.ServiceOperation.OperationParameterBindingKind == OperationParameterBindingKind.Sometimes || this.ServiceOperation.OperationParameterBindingKind == OperationParameterBindingKind.Never");
                break;
            }

            ReadOnlyCollection <OperationParameter> operationParameters = operation.Parameters;
            if (operationParameters != null && operationParameters.Count > 0)
            {
                List <IEdmOperationParameter> list = new List <IEdmOperationParameter>(operationParameters.Count);
                foreach (OperationParameter parameter in operationParameters)
                {
                    IEdmTypeReference     parameterType = this.model.EnsureTypeReference(parameter.ParameterType, /*annotations*/ null);
                    EdmOperationParameter edmParameter  = new EdmOperationParameter(this, parameter.Name, parameterType);
                    list.Add(edmParameter);
                }

                this.parameters = new ReadOnlyCollection <IEdmOperationParameter>(list);
            }

            this.ReturnType = this.CreateReturnTypeReference();
        }
        /// <summary>
        /// Retrieve the related end for the given resource set, type and property.
        /// </summary>
        /// <param name="resourceSet">resource set for the source end</param>
        /// <param name="resourceType">resource type for the source end</param>
        /// <param name="resourceProperty">resource property for the source end</param>
        /// <returns>Related resource association set end for the given parameters</returns>
        internal ResourceAssociationSetEnd GetRelatedResourceAssociationSetEnd(ResourceSetWrapper resourceSet, ResourceType resourceType, ResourceProperty resourceProperty)
        {
            Debug.Assert(resourceSet != null, "resourceSet != null");
            Debug.Assert(resourceType != null, "resourceType != null");

            ResourceAssociationSetEnd thisEnd = this.GetResourceAssociationSetEnd(resourceSet, resourceType, resourceProperty);

            if (thisEnd != null)
            {
                return thisEnd == this.End1 ? this.End2 : this.End1;
            }

            return null;
        }
        /// <summary>Composes all query interceptors into a single expression.</summary>
        /// <param name="serviceInstance">Web service instance.</param>
        /// <param name="container">Container for which interceptors should run.</param>
        /// <returns>An expression the filter for query interceptors, possibly null.</returns>
        internal static Expression ComposeQueryInterceptors(object serviceInstance, ResourceSetWrapper container)
        {
            Debug.Assert(container != null, "container != null");
            MethodInfo[] methods = container.QueryInterceptors;
            if (methods == null || methods.Length == 0)
            {
                return null;
            }

            LambdaExpression filter = null;
            for (int i = 0; i < methods.Length; i++)
            {
                Expression predicate;
                try
                {
                    predicate = (Expression)methods[i].Invoke(serviceInstance, WebUtil.EmptyObjectArray);
                }
                catch (TargetInvocationException tie)
                {
                    ErrorHandler.HandleTargetInvocationException(tie);
                    throw;
                }

                if (predicate == null)
                {
                    throw new InvalidOperationException(Strings.DataService_AuthorizationReturnedNullQuery(methods[i].Name, methods[i].DeclaringType.FullName));
                }

                // predicate is LambdaExpression -- otherwise signature check missed something and following cast would throw
                LambdaExpression lambdaPredicate = ((LambdaExpression)predicate);

                if (filter == null)
                {
                    filter = lambdaPredicate;
                }
                else
                {
                    ParameterExpression parameter = filter.Parameters[0];
                    Expression adjustedPredicate = ParameterReplacerVisitor.Replace(
                        lambdaPredicate.Body,             // expression
                        lambdaPredicate.Parameters[0],    // oldParameter
                        parameter);                                     // newParameter
                    filter = Expression.Lambda(Expression.And(filter.Body, adjustedPredicate), parameter);
                }
            }

            return filter;
        }
        /// <summary>
        /// Composes the specified <paramref name="queryExpression"/> for the 
        /// given <paramref name="container"/> with authorization
        /// callbacks.
        /// </summary>
        /// <param name="service">Data service on which to invoke method.</param>
        /// <param name="container">resource set to compose with.</param>
        /// <param name="queryExpression">Query to compose.</param>
        /// <returns>The resulting composed query.</returns>
        internal static Expression ComposeResourceContainer(IDataService service, ResourceSetWrapper container, Expression queryExpression)
        {
            Debug.Assert(service != null, "service != null");
            Debug.Assert(container != null, "container != null");
            Debug.Assert(queryExpression != null, "queryExpression != null");

            MethodInfo[] methods = container.QueryInterceptors;
            if (methods != null)
            {
                for (int i = 0; i < methods.Length; i++)
                {
                    Expression predicate;
                    try
                    {
                        predicate = (Expression)methods[i].Invoke(service.Instance, WebUtil.EmptyObjectArray);
                    }
                    catch (TargetInvocationException tie)
                    {
                        ErrorHandler.HandleTargetInvocationException(tie);
                        throw;
                    }

                    if (predicate == null)
                    {
                        throw new InvalidOperationException(Strings.DataService_AuthorizationReturnedNullQuery(methods[i].Name, methods[i].DeclaringType.FullName));
                    }

                    // predicate is LambdaExpression -- otherwise signature check missed something and following cast would throw
                    queryExpression = queryExpression.QueryableWhere((LambdaExpression)predicate);
                }
            }

            return queryExpression;
        }
        /// <summary>
        /// Match navigation properties with their partners for the given resource set.
        /// </summary>
        /// <param name="resourceSet">The resource set to supply the necessary data for matchign up the navigation properties.</param>
        /// <remarks>
        /// Materialization state: Full required. No change in materialization state.
        /// Cache state: none required. No change in cache state.
        /// </remarks>
        private void PairUpNavigationPropertiesForEntitySet(ResourceSetWrapper resourceSet)
        {
            Debug.Assert(resourceSet != null, "resourceSet != null");
            this.AssertMaterializationState(MetadataProviderState.Full);

            // Populate for derived types
            foreach (ResourceType derivedType in this.MetadataProvider.GetDerivedTypes(resourceSet.ResourceType))
            {
                this.PairUpNavigationPropertiesForEntitySetAndType(resourceSet, derivedType);
            }

            // Populate for this type and its base types
            ResourceType resourceType = resourceSet.ResourceType;
            while (resourceType != null)
            {
                this.PairUpNavigationPropertiesForEntitySetAndType(resourceSet, resourceType);
                resourceType = resourceType.BaseType;
            }
        }
 /// <summary>Checks whether this request has the specified reading rights.</summary>
 /// <param name="container">Container to check.</param>
 /// <param name="singleResult">Whether a single or multiple resources are requested.</param>
 /// <exception cref="DataServiceException">Thrown if <paramref name="singleResult"/> aren't available.</exception>
 internal static void CheckResourceRightsForRead(ResourceSetWrapper container, bool singleResult)
 {
     Debug.Assert(container != null, "container != null");
     EntitySetRights requiredRights = singleResult ? EntitySetRights.ReadSingle : EntitySetRights.ReadMultiple;
     CheckResourceRights(container, requiredRights);
 }
        /// <summary>
        /// Add the given entity set to the model.
        /// </summary>
        /// <param name="resourceSet">ResourceSetWrapper instance to add.</param>
        /// <returns>an instance of IEdmEntitySet for the given <paramref name="resourceSet"/>.</returns>
        internal IEdmEntitySet EnsureEntitySet(ResourceSetWrapper resourceSet)
        {
            this.EnsureDefaultEntityContainer();

            // Make sure if the entity container exists
            string entityContainerName = resourceSet.EntityContainerName ?? this.metadataProvider.ContainerName;
            MetadataProviderEdmEntityContainer entityContainer = this.FindExistingEntityContainer(entityContainerName);
            if (entityContainer == null)
            {
                entityContainer = new MetadataProviderEdmEntityContainer(this, entityContainerName, this.GetContainerNamespace());
                MetadataProviderUtils.ConvertCustomAnnotations(this, this.metadataProvider.GetEntityContainerAnnotations(entityContainerName), entityContainer);
                this.entityContainerCache.Add(entityContainerName, entityContainer);
                this.entityContainerCache.Add(entityContainer.FullName(), entityContainer);
            }

            string entitySetName = MetadataProviderUtils.GetEntitySetName(resourceSet.ResourceSet);
            IEdmEntitySet entitySet = entityContainer.FindEntitySet(entitySetName);
            if (entitySet == null)
            {
                entitySet = entityContainer.AddEntitySet(entitySetName, resourceSet);
            }

            return entitySet;
        }
        /// <summary>Creates new instance of node representing expanded navigation property.</summary>
        /// <param name="propertyName">The name of the property to project and expand.</param>
        /// <param name="property">The <see cref="ResourceProperty"/> for this property. Can only be null for the root node.</param>
        /// <param name="targetResourceType">Target resource type on which the expansion needs to happen.</param>
        /// <param name="resourceSetWrapper">The resource set to which the expansion leads.</param>
        /// <param name="orderingInfo">The ordering info for this node. null means no ordering to be applied.</param>
        /// <param name="filter">The filter for this node. null means no filter to be applied.</param>
        /// <param name="skipCount">Number of results to skip. null means no results to be skipped.</param>
        /// <param name="takeCount">Maximum number of results to return. null means return all available results.</param>
        /// <param name="maxResultsExpected">Maximum number of expected results. Hint that the provider should return
        /// at least maxResultsExpected + 1 results (if available).</param>
        /// <param name="selectExpandClause">The select expand clause for the current node from the URI Parser.</param>
        internal ExpandedProjectionNode(
            string propertyName,
            ResourceProperty property,
            ResourceType targetResourceType,
            ResourceSetWrapper resourceSetWrapper,
            OrderingInfo orderingInfo,
            Expression filter,
            int? skipCount,
            int? takeCount,
            int? maxResultsExpected,
            SelectExpandClause selectExpandClause)
            : base(propertyName, property, targetResourceType)
        {
            Debug.Assert(resourceSetWrapper != null, "resourceSetWrapper != null");
            Debug.Assert(property != null || (propertyName.Length == 0 && targetResourceType == null), "We don't support open navigation properties.");
            Debug.Assert(property == null || targetResourceType.TryResolvePropertyName(property.Name) != null, "Property must exist on the target resource type");
            Debug.Assert(selectExpandClause != null, "selectExpandClause != null");

            this.resourceSetWrapper = resourceSetWrapper;
            this.orderingInfo = orderingInfo;
            this.filter = filter;
            this.skipCount = skipCount;
            this.takeCount = takeCount;
            this.maxResultsExpected = maxResultsExpected;
            this.nodes = new List<ProjectionNode>();
            this.hasExpandedPropertyOnDerivedType = false;
            this.selectExpandClause = selectExpandClause;
        }
Esempio n. 36
0
        /// <summary>
        /// If the provider implements IConcurrencyProvider, then this method passes the etag values
        /// to the provider, otherwise compares the etag itself.
        /// </summary>
        /// <param name="resourceCookie">etag values for the given resource.</param>
        /// <param name="container">container for the given resource.</param>
        internal void SetETagValues(object resourceCookie, ResourceSetWrapper container)
        {
            Debug.Assert(resourceCookie != null, "resourceCookie != null");
            Debug.Assert(container != null, "container != null");
            AstoriaRequestMessage host = this.service.OperationContext.RequestMessage;
            Debug.Assert(String.IsNullOrEmpty(host.GetRequestIfNoneMatchHeader()), "IfNoneMatch header cannot be specified for Update/Delete operations");

            // Resolve the cookie first to the actual resource type
            object actualEntity = this.ResolveResource(resourceCookie);
            Debug.Assert(actualEntity != null, "actualEntity != null");

            ResourceType resourceType = WebUtil.GetNonPrimitiveResourceType(this.service.Provider, actualEntity);
            Debug.Assert(resourceType != null, "resourceType != null");

            IList<ResourceProperty> etagProperties = this.service.Provider.GetETagProperties(container.Name, resourceType);

            if (etagProperties.Count == 0)
            {
                if (!String.IsNullOrEmpty(host.GetRequestIfMatchHeader()))
                {
                    throw DataServiceException.CreateBadRequestError(Strings.Serializer_NoETagPropertiesForType);
                }

                // If the type has no etag properties, then we do not need to do any etag checks
                return;
            }

            // If the provider implements IConcurrencyProvider, then we need to call the provider
            // and pass the etag values. Else, we need to compare the etag values ourselves.
            IDataServiceUpdateProvider concurrencyProvider = this.updateProvider as IDataServiceUpdateProvider;
            if (concurrencyProvider != null)
            {
                bool? checkForEquality = null;
                IEnumerable<KeyValuePair<string, object>> etagValues;
                if (!String.IsNullOrEmpty(host.GetRequestIfMatchHeader()))
                {
                    checkForEquality = true;
                    etagValues = ParseETagValue(etagProperties, host.GetRequestIfMatchHeader());
                }
                else
                {
                    etagValues = WebUtil.EmptyKeyValuePairStringObject;
                }

                concurrencyProvider.SetConcurrencyValues(resourceCookie, checkForEquality, etagValues);
            }
            else if (String.IsNullOrEmpty(host.GetRequestIfMatchHeader()))
            {
                throw DataServiceException.CreateBadRequestError(Strings.DataService_CannotPerformOperationWithoutETag(resourceType.FullName));
            }
            else if (host.GetRequestIfMatchHeader() != XmlConstants.HttpAnyETag)
            {
                // Compare If-Match header value with the current etag value, if the If-Match header value is not equal to '*'
                string etagValue = WebUtil.GetETagValue(resourceCookie, resourceType, etagProperties, this.service, false /*getMethod*/);
                Debug.Assert(!String.IsNullOrEmpty(etagValue), "etag value can never be null");

                if (etagValue != host.GetRequestIfMatchHeader())
                {
                    throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch);
                }
            }
        }
Esempio n. 37
0
        /// <summary>
        /// Gets the result set for the operation.
        /// </summary>
        /// <param name="provider">Provider instance to resolve the path expression.</param>
        /// <param name="bindingSet">Binding resource set.</param>
        /// <returns>Returns the result resource set for the operation.</returns>
        internal ResourceSetWrapper GetResultSet(DataServiceProviderWrapper provider, ResourceSetWrapper bindingSet)
        {
#if DEBUG
            Debug.Assert(this.isReadOnly, "Wrapper class has not been initialized yet.");
#endif
            if (this.resourceSet != null)
            {
                Debug.Assert(this.resourceSet.ResourceSet == this.operation.ResourceSet, "this.resourceSet.ResourceSet == this.serviceOperation.ResourceSet");
                Debug.Assert(this.ResultSetPathExpression == null, "this.ResultSetPathExpression == null");
                return this.resourceSet;
            }
            
            if (this.ResultSetPathExpression != null)
            {
                Debug.Assert(provider != null, "provider != null");
                if (bindingSet == null)
                {
                    throw new InvalidOperationException(Strings.OperationWrapper_PathExpressionRequiresBindingSet(this.Name));
                }

                ResourceSetWrapper resultSet = this.ResultSetPathExpression.GetTargetSet(provider, bindingSet);
                if (resultSet == null)
                {
                    throw new InvalidOperationException(Strings.OperationWrapper_TargetSetFromPathExpressionNotNotVisible(this.Name, this.ResultSetPathExpression.PathExpression, bindingSet.Name));
                }

                return resultSet;
            }

            return null;
        }
        /// <summary>
        /// Adds an entity set backed by the <paramref name="resourceSet"/> to the entity container.
        /// </summary>
        /// <param name="entitySetName">The name of the entity set.</param>
        /// <param name="resourceSet">The resource set backing the entity set to be created.</param>
        /// <returns>an instance of IEdmEntitySet that just got added.</returns>
        /// <remarks>
        /// This method will also create the association sets and associations for the entity set.
        /// Materialization state: EntityContainers required. No change in materialization state.
        /// </remarks>
        internal IEdmEntitySet AddEntitySet(string entitySetName, ResourceSetWrapper resourceSet)
        {
            Debug.Assert(!string.IsNullOrEmpty(entitySetName), "!string.IsNullOrEmpty(entitySetName)");
            Debug.Assert(resourceSet != null, "resourceSet != null");

            IEdmEntitySet entitySet = new MetadataProviderEdmEntitySet(this.model, this, resourceSet);
            MetadataProviderUtils.ConvertCustomAnnotations(this.model, resourceSet.CustomAnnotations, entitySet);
            this.entitySetCache.Add(entitySetName, entitySet);
            return entitySet;
        }
        /// <summary>Match navigation properties with their partners for the given set and type</summary>
        /// <param name="resourceSet">Resource type to inspect.</param>
        /// <param name="resourceType">Resource set to inspect.</param>
        /// <remarks>
        /// Materialization state: Full required. No change in materialization state.
        /// Cache state: none required. No change in cache state.
        /// </remarks>
        private void PairUpNavigationPropertiesForEntitySetAndType(ResourceSetWrapper resourceSet, ResourceType resourceType)
        {
            Debug.Assert(resourceSet != null, "resourceSet != null");
            Debug.Assert(resourceType != null, "resourceType != null");
            this.AssertMaterializationState(MetadataProviderState.Full);

            IEnumerable<ResourceProperty> resourceProperties = resourceType.PropertiesDeclaredOnThisType;
            if (resourceProperties != null)
            {
                foreach (ResourceProperty navigationProperty in resourceProperties.Where(p => p.TypeKind == ResourceTypeKind.EntityType))
                {
                    // For every nav property, hook it up to its partner.
                    this.PairUpNavigationProperty(resourceSet, resourceType, navigationProperty);
                }
            }
        }
Esempio n. 40
0
        /// <summary>
        /// Tracks the specified <paramref name="target"/> for a 
        /// given <paramref name="action "/> on the <paramref name="container"/>.
        /// </summary>
        /// <param name="target">Object to be tracked.</param>
        /// <param name="container">Container in which object is changed.</param>
        /// <param name="action">Action affecting target.</param>
        /// <remarks>
        /// If <paramref name="target"/> was already being tracked, the actions are OR'ed together.
        /// </remarks>
        internal void TrackAction(object target, ResourceSetWrapper container, UpdateOperations action)
        {
            AssertActionValues(target, container);
            Debug.Assert(this.items != null, "this.items != null - otherwise FireNotification has already been called");

            // If it won't be necessary for us to fire authorizatio methods,
            // skip tracking altogether.
            if (container.ChangeInterceptors == null)
            {
                return;
            }

            // Get the container for which the change has taken place.
            Dictionary<object, UpdateOperations> changedItems;
            if (!this.items.TryGetValue(container, out changedItems))
            {
                // In order to mantain backwards compatibility, we are going to use default comparer for V1
                // providers. However, for V2 providers we are going to do reference equality comparisons.
                if (this.service.Provider.HasReflectionOrEFProviderQueryBehavior)
                {
                    changedItems = new Dictionary<object, UpdateOperations>(EqualityComparer<object>.Default);
                }
                else
                {
                    changedItems = new Dictionary<object, UpdateOperations>(ReferenceEqualityComparer<object>.Instance);
                }

                this.items.Add(container, changedItems);
            }

            UpdateOperations existingAction;
            if (changedItems.TryGetValue(target, out existingAction))
            {
                if ((action | existingAction) != existingAction)
                {
                    changedItems[target] = action | existingAction;
                }
            }
            else
            {
                changedItems.Add(target, action);
            }
        }
        /// <summary>
        /// Fills in the rest of required information for navigation properties.
        /// </summary>
        /// <param name="resourceSet">Resource set to inspect.</param>
        /// <param name="resourceType">Resource type to inspect.</param>
        /// <param name="navigationProperty">Navigation property to inspect.</param>
        internal void PairUpNavigationProperty(ResourceSetWrapper resourceSet, ResourceType resourceType, ResourceProperty navigationProperty)
        {
            Debug.Assert(resourceSet != null, "resourceSet != null");
            Debug.Assert(resourceType != null, "resourceType != null");
            Debug.Assert(navigationProperty != null && navigationProperty.ResourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "navigationProperty != null && navigationProperty.ResourceType.ResourceTypeKind == ResourceTypeKind.EntityType");
            Debug.Assert(resourceType.TryResolvePropertiesDeclaredOnThisTypeByName(navigationProperty.Name) != null, "navigationProperty must be declared on resourceType.");

            string associationSetKey = resourceSet.Name + '_' + resourceType.FullName + '_' + navigationProperty.Name;

            // We changed the association logic on the server to create the correct navigation property for V4 to run the tests.
            // The association logic on server side needs to be removed.
            // Check the cache first; we might already have visited the partiner of this navigation property.
            if (this.associationSetByKeyCache.ContainsKey(associationSetKey))
            {
                return;
            }

            ResourceAssociationSet resourceAssociationSet = this.MetadataProvider.GetResourceAssociationSet(resourceSet, resourceType, navigationProperty);

            if (resourceAssociationSet != null)
            {
                this.PairUpNavigationPropertyWithResourceAssociationSet(resourceAssociationSet);
                this.associationSetByKeyCache.Add(associationSetKey, resourceAssociationSet.Name);
            }
        }
Esempio n. 42
0
        /// <summary>
        /// Determines the minimum version that can be used for this specific type.
        /// 
        /// Note: if you don't know the specific type only the set, you will need to find the maximum of this
        ///       for all types in the hierarchy for the set type see ResourceSetWrapper.MinimumPayloadVersion
        /// </summary>
        /// <param name="service">The data service instance</param>
        /// <param name="resourceSet">The set that the type belongs to.</param>
        /// <returns>The minimum version that can be used for a payload of this specific type.</returns>
        internal Version GetMinimumResponseVersion(IDataService service, ResourceSetWrapper resourceSet)
        {
            Debug.Assert(resourceSet.ResourceType.IsAssignableFrom(this), "The passed in resourceSet does not include this type");
            Version minimumVersion = VersionUtil.Version4Dot0;

            // If target set contains collection properties we need v4.0
            // If target type contains named streams, we need v4.0
            minimumVersion = VersionUtil.RaiseVersion(minimumVersion, this.GetMinimumProtocolVersion());

            // If the resource type is an open type, then we do not know the metadata of the open property and hence cannot
            // predict the response version. Hence we need to bump the version to the maximum, 
            // and if we encounter during serialization, anything greater than the computed response version, we will throw instream error.
            if (this.IsOpenType)
            {
                Version maxProtocolVersion = service.Configuration.DataServiceBehavior.MaxProtocolVersion.ToVersion();
                Version requestMaxVersion = service.OperationContext.RequestMessage.RequestMaxVersion;
                Version responseVersion = (requestMaxVersion < maxProtocolVersion) ? requestMaxVersion : maxProtocolVersion;
                minimumVersion = VersionUtil.RaiseVersion(minimumVersion, responseVersion);
            }

            return minimumVersion;
        }