Beispiel #1
0
        /// <summary>
        /// Creates the wrapper from the given service operation.
        /// </summary>
        /// <param name="serviceOperation">Service operation instance whose wrapper needs to get created.</param>
        /// <param name="resourceSetValidator">Resource set validator.</param>
        /// <param name="resourceTypeValidator">Resource type validator.</param>
        /// <returns>Wrapper for the given service operation.</returns>
        internal static ServiceOperationWrapper CreateServiceOperationWrapper(
            ServiceOperation serviceOperation,
            Func <ResourceSet, ResourceSetWrapper> resourceSetValidator,
            Func <ResourceType, ResourceType> resourceTypeValidator)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(serviceOperation != null, "serviceOperation != null");
            Debug.Assert(serviceOperation.IsReadOnly, "The serviceOperation must be read-only by now.");
            Debug.Assert(resourceSetValidator != null, "resourceSetValidator != null");
            Debug.Assert(resourceTypeValidator != null, "resourceTypeValidator != null");

            ServiceOperationWrapper serviceOperationWrapper = new ServiceOperationWrapper(serviceOperation);

#if DEBUG
            serviceOperationWrapper.isReadOnly = true;
#endif

            serviceOperationWrapper.resourceSet = resourceSetValidator(serviceOperation.ResourceSet);
            ResourceType resultType = serviceOperation.ResultType;
            if (resultType == null || resultType.ResourceTypeKind == ResourceTypeKind.Primitive)
            {
                // No need to validate primitive resource types
                serviceOperationWrapper.resultType = resultType;
            }
            else
            {
                // Validate the resource type of the result
                serviceOperationWrapper.resultType = resourceTypeValidator(resultType);
            }

            return(serviceOperationWrapper);
        }
        /// <summary>
        /// Validates if the service operation should be visible and is read only. If the service operation
        /// rights are set to None the service operation should not be visible.
        /// </summary>
        /// <param name="serviceOperation">Service operation to be validated.</param>
        /// <returns>Validated service operation, null if the service operation is not supposed to be visible.</returns>
        internal ServiceOperationWrapper ValidateServiceOperation(ServiceOperation serviceOperation)
        {
            DebugUtils.CheckNoExternalCallers();

            ServiceOperationWrapper serviceOperationWrapper = null;

            if (serviceOperation != null)
            {
                // For IDSP, we want to make sure the metadata object instance stay the same within
                // a request because we do reference comparisons.  Note the provider can return
                // different metadata instances within the same request.  The the Validate*() methods
                // will make sure to return the first cached instance.
                if (!this.serviceOperationCache.TryGetValue(serviceOperation.Name, out serviceOperationWrapper))
                {
                    ValidateServiceOperationReadOnly(serviceOperation);
                    serviceOperationWrapper = ServiceOperationWrapper.CreateServiceOperationWrapper(serviceOperation, this.ValidateResourceSet, this.ValidateResourceType);
                    this.serviceOperationCache[serviceOperation.Name] = serviceOperationWrapper;
                }
            }

            return(serviceOperationWrapper);
        }
        /// <summary>
        /// Binds the service operation parameters from query options.
        /// </summary>
        /// <param name="serviceOperation">The service operation to bind the parameters for.</param>
        /// <returns>Enumeration of parameter values for the service operation.</returns>
        private IEnumerable<QueryNode> BindServiceOperationParameters(ServiceOperationWrapper serviceOperation)
        {
            Debug.Assert(serviceOperation != null, "serviceOperation != null");

            //// This is a copy of RequestUriProcessor.ReadOperationParameters

            if (serviceOperation.Parameters.Count == 0)
            {
                return null;
            }

            List<QueryNode> parameters = new List<QueryNode>(serviceOperation.Parameters.Count);
            for (int i = 0; i < serviceOperation.Parameters.Count; i++)
            {
                ServiceOperationParameter serviceOperationParameter = serviceOperation.Parameters[i];
                Type parameterType = serviceOperationParameter.ParameterType.InstanceType;
                Type nonNullableParameterType = Nullable.GetUnderlyingType(parameterType) ?? parameterType;
                string parameterTextValue = this.ConsumeQueryOption(serviceOperationParameter.Name);
                object parameterValue;
                if (string.IsNullOrEmpty(parameterTextValue))
                {
                    if (!parameterType.IsClass && (parameterType == nonNullableParameterType))
                    {
                        // The target parameter type is non-nullable, but we found null value, this usually means that the parameter is missing
                        throw new ODataException(Strings.MetadataBinder_ServiceOperationParameterMissing(serviceOperation.Name, serviceOperationParameter.Name));
                    }

                    parameterValue = null;
                }
                else
                {
                    // We choose to be a little more flexible than with keys and
                    // allow surrounding whitespace (which is never significant).
                    parameterTextValue = parameterTextValue.Trim();
                    if (!UriPrimitiveTypeParser.TryUriStringToPrimitive(parameterTextValue, parameterType, out parameterValue))
                    {
                        throw new ODataException(Strings.MetadataBinder_ServiceOperationParameterInvalidType(serviceOperationParameter.Name, parameterTextValue, serviceOperation.Name, serviceOperationParameter.ParameterType.FullName));
                    }
                }

                parameters.Add(new ConstantQueryNode() { Value = parameterValue });
            }

            return new ReadOnlyCollection<QueryNode>(parameters);
        }
        /// <summary>
        /// Binds a service operation segment.
        /// </summary>
        /// <param name="segmentToken">The segment which represents a service operation.</param>
        /// <param name="serviceOperation">The service operation to bind.</param>
        /// <returns>The bound node.</returns>
        private QueryNode BindServiceOperation(SegmentQueryToken segmentToken, ServiceOperationWrapper serviceOperation)
        {
            Debug.Assert(segmentToken != null, "segmentToken != null");
            Debug.Assert(serviceOperation != null, "serviceOperation != null");
            Debug.Assert(segmentToken.Name == serviceOperation.Name, "The segment represents a different service operation.");

            //// This is a metadata copy of the RequestUriProcessor.CreateSegmentForServiceOperation

            //// The WCF DS checks the verb in this place, we can't do that here

            // All service operations other than those returning IQueryable MUST NOT have () appended to the URI
            // V1/V2 behavior: if it's IEnumerable<T>, we do not allow () either, because it's not further composable.
            if (serviceOperation.ResultKind != ServiceOperationResultKind.QueryWithMultipleResults && 
                segmentToken.NamedValues != null)
            {
                throw new ODataException(Strings.MetadataBinder_NonQueryableServiceOperationWithKeyLookup(segmentToken.Name));
            }

            IEnumerable<QueryNode> serviceOperationParameters = this.BindServiceOperationParameters(serviceOperation);
            switch (serviceOperation.ResultKind)
            {
                case ServiceOperationResultKind.QueryWithMultipleResults:
                    if (serviceOperation.ResultType.ResourceTypeKind != ResourceTypeKind.EntityType)
                    {
                        throw new ODataException(Strings.MetadataBinder_QueryServiceOperationOfNonEntityType(serviceOperation.Name, serviceOperation.ResultKind.ToString(), serviceOperation.ResultType.FullName));
                    }

                    CollectionServiceOperationQueryNode collectionServiceOperationQueryNode = new CollectionServiceOperationQueryNode()
                    {
                        ServiceOperation = serviceOperation.ServiceOperation,
                        Parameters = serviceOperationParameters
                    };

                    if (segmentToken.NamedValues != null)
                    {
                        return this.BindKeyValues(collectionServiceOperationQueryNode, segmentToken.NamedValues);
                    }
                    else
                    {
                        return collectionServiceOperationQueryNode;
                    }

                case ServiceOperationResultKind.QueryWithSingleResult:
                    if (serviceOperation.ResultType.ResourceTypeKind != ResourceTypeKind.EntityType)
                    {
                        throw new ODataException(Strings.MetadataBinder_QueryServiceOperationOfNonEntityType(serviceOperation.Name, serviceOperation.ResultKind.ToString(), serviceOperation.ResultType.FullName));
                    }

                    return new SingleValueServiceOperationQueryNode()
                    {
                        ServiceOperation = serviceOperation.ServiceOperation,
                        Parameters = serviceOperationParameters
                    };

                case ServiceOperationResultKind.DirectValue:
                    if (serviceOperation.ResultType.ResourceTypeKind == ResourceTypeKind.Primitive)
                    {
                        // Direct primitive values are composable, $value is allowed on them.
                        return new SingleValueServiceOperationQueryNode()
                        {
                            ServiceOperation = serviceOperation.ServiceOperation,
                            Parameters = serviceOperationParameters
                        };
                    }
                    else
                    {
                        // Direct non-primitive values are not composable at all
                        return new UncomposableServiceOperationQueryNode()
                        {
                            ServiceOperation = serviceOperation.ServiceOperation,
                            Parameters = serviceOperationParameters
                        };
                    }

                case ServiceOperationResultKind.Enumeration:
                case ServiceOperationResultKind.Void:
                    // Enumeration and void service operations are not composable
                    return new UncomposableServiceOperationQueryNode()
                    {
                        ServiceOperation = serviceOperation.ServiceOperation,
                        Parameters = serviceOperationParameters
                    };

                default:
                    throw new ODataException(Strings.General_InternalError(InternalErrorCodes.MetadataBinder_BindServiceOperation));
            }
        }
        /// <summary>Checks whether this request has the specified rights.</summary>
        /// <param name="operation">Operation 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 CheckServiceRights(ServiceOperationWrapper operation, bool singleResult)
        {
            Debug.Assert(operation != null, "operation != null");

            if (operation.ResultKind != ServiceOperationResultKind.Void)
            {
                ServiceOperationRights requiredRights = singleResult ? ServiceOperationRights.ReadSingle : ServiceOperationRights.ReadMultiple;
                CheckServiceRights(operation, requiredRights);
            }
        }
        /// <summary>Checks whether this request has the specified rights.</summary>
        /// <param name="operation">Operation to check.</param>
        /// <param name="requiredRights">Required rights.</param>
        /// <exception cref="DataServiceException">Thrown if <paramref name="requiredRights"/> aren't available.</exception>
        internal static void CheckServiceRights(ServiceOperationWrapper operation, ServiceOperationRights requiredRights)
        {
            Debug.Assert(operation != null, "operation != null");
            Debug.Assert(requiredRights != ServiceOperationRights.None, "requiredRights != EntitySetRights.None");

            ServiceOperationRights effectiveRights = operation.Rights;
            if ((requiredRights & effectiveRights) == 0)
            {
                throw DataServiceException.CreateForbidden();
            }
        }
Beispiel #7
0
            /// <summary>Populate resource types returned by the given service operation.</summary>
            /// <param name="serviceOperation">Service operation to inspect</param>
            private void PopulateTypeForServiceOperation(ServiceOperationWrapper serviceOperation)
            {
                Debug.Assert(serviceOperation != null, "serviceOperation != null");

                ResourceType resultType = serviceOperation.ResultType;
                if (resultType != null && resultType.ResourceTypeKind == ResourceTypeKind.ComplexType)
                {
                    this.AddVisibleResourceType(resultType);
                    this.AddComplexPropertTypes(resultType);
                }

                Debug.Assert(
                    resultType == null || resultType.ResourceTypeKind != ResourceTypeKind.EntityType ||
                    (this.resourceTypes.ContainsKey(resultType.Namespace) && this.resourceTypes[resultType.Namespace].Contains(resultType)),
                    "If a result type is an entity type, it must be visible through an entity set.");
            }
		/// <summary>
		/// Creates the wrapper from the given service operation.
		/// </summary>
		/// <param name="serviceOperation">Service operation instance whose wrapper needs to get created.</param>
		/// <param name="resourceSetValidator">Resource set validator.</param>
		/// <param name="resourceTypeValidator">Resource type validator.</param>
		/// <returns>Wrapper for the given service operation.</returns>
		public static ServiceOperationWrapper CreateServiceOperationWrapper(
			ServiceOperation serviceOperation,
			Func<ResourceSet, ResourceSetWrapper> resourceSetValidator,
			Func<ResourceType, ResourceType> resourceTypeValidator)
		{
			DebugUtils.CheckNoExternalCallers();
			Debug.Assert(serviceOperation != null, "serviceOperation != null");
			Debug.Assert(serviceOperation.IsReadOnly, "The serviceOperation must be read-only by now.");
			Debug.Assert(resourceSetValidator != null, "resourceSetValidator != null");
			Debug.Assert(resourceTypeValidator != null, "resourceTypeValidator != null");

			ServiceOperationWrapper serviceOperationWrapper = new ServiceOperationWrapper(serviceOperation);
#if DEBUG
			serviceOperationWrapper.isReadOnly = true;
#endif

			serviceOperationWrapper.resourceSet = resourceSetValidator(serviceOperation.ResourceSet);
			ResourceType resultType = serviceOperation.ResultType;
			if (resultType == null || resultType.ResourceTypeKind == ResourceTypeKind.Primitive)
			{
				// No need to validate primitive resource types
				serviceOperationWrapper.resultType = resultType;
			}
			else
			{
				// Validate the resource type of the result
				serviceOperationWrapper.resultType = resourceTypeValidator(resultType);
			}

			return serviceOperationWrapper;
		}