private static IEdmEntityType CreateModelAndGetEdmType(ResourceType resourceType)
        {
            var provider = new DataServiceProviderSimulator();
            DataServiceSimulator dataService = new DataServiceSimulator();

            DataServiceStaticConfiguration staticConfiguration = new DataServiceStaticConfiguration(dataService.Instance.GetType(), provider);
            IDataServiceProviderBehavior   providerBehavior    = DataServiceProviderBehavior.CustomDataServiceProviderBehavior;

            DataServiceProviderWrapper providerWrapper = new DataServiceProviderWrapper(
                new DataServiceCacheItem(
                    new DataServiceConfiguration(provider),
                    staticConfiguration),
                provider,
                provider,
                dataService,
                false);

            dataService.Provider = providerWrapper;
            var model = new MetadataProviderEdmModel(providerWrapper, new DataServiceStreamProviderWrapper(dataService), DataServiceActionProviderWrapper.Create(dataService));

            dataService.ProcessingPipeline          = new DataServiceProcessingPipeline();
            model.MetadataProvider.ProviderBehavior = providerBehavior;

            var edmType = model.EnsureSchemaType(resourceType) as IEdmEntityType;

            return(edmType);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="MetadataProviderEdmActionImport"/> class.
 /// </summary>
 /// <param name="model">The model this instance belongs to.</param>
 /// <param name="operation">The resource operation underlying this action import.</param>
 /// <param name="namespaceName">The namespace of the EdmOperation.</param>
 /// <remarks>
 /// This constructor assumes that the entity set for this service operation has already be created.
 /// </remarks>
 internal MetadataProviderEdmAction(
     MetadataProviderEdmModel model,
     OperationWrapper operation,
     string namespaceName)
     : base(model, operation, namespaceName)
 {
 }
Esempio n. 3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MetadataProviderEdmActionImport"/> class.
 /// </summary>
 /// <param name="model">The model this instance belongs to.</param>
 /// <param name="container">The container this instance belongs to.</param>
 /// <param name="action">The edm action object underlying this function import.</param>
 /// <remarks>
 /// This constructor assumes that the entity set for this service operation has already be created.
 /// </remarks>
 internal MetadataProviderEdmActionImport(
     MetadataProviderEdmModel model,
     MetadataProviderEdmEntityContainer container,
     MetadataProviderEdmAction action)
     : base(model, container, action)
 {
     this.Action = action;
 }
Esempio n. 4
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MetadataProviderEdmFunctionImport"/> class.
 /// </summary>
 /// <param name="model">The model this instance belongs to.</param>
 /// <param name="container">The container this instance belongs to.</param>
 /// <param name="function">The function that is being imported.</param>
 /// <remarks>
 /// This constructor assumes that the entity set for this service operation has already be created.
 /// </remarks>
 internal MetadataProviderEdmFunctionImport(
     MetadataProviderEdmModel model,
     MetadataProviderEdmEntityContainer container,
     MetadataProviderEdmFunction function)
     : base(model, container, function)
 {
     this.Function = function;
 }
Esempio n. 5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Microsoft.OData.Service.ExpandAndSelectParseResult"/> class.
        /// </summary>
        /// <param name="requestDescription">The request description.</param>
        /// <param name="dataService">The data service.</param>
        internal ExpandAndSelectParseResult(RequestDescription requestDescription, IDataService dataService)
        {
            Debug.Assert(dataService != null, "dataService != null");
            Debug.Assert(dataService.OperationContext != null, "dataService.OperationContext != null");
            Debug.Assert(dataService.OperationContext.RequestMessage != null, "dataService.OperationContext.RequestMessage != null");

            string expand = dataService.OperationContext.RequestMessage.GetQueryStringItem(XmlConstants.HttpQueryStringExpand);

            this.RawSelectQueryOptionValue = dataService.OperationContext.RequestMessage.GetQueryStringItem(XmlConstants.HttpQueryStringSelect);

            ResourceType       targetResourceType = requestDescription.TargetResourceType;
            ResourceSetWrapper targetResourceSet  = requestDescription.TargetResourceSet;

            if (!string.IsNullOrEmpty(expand))
            {
                if (targetResourceType == null || targetResourceType.ResourceTypeKind != ResourceTypeKind.EntityType || targetResourceSet == null)
                {
                    throw DataServiceException.CreateBadRequestError(Strings.RequestQueryProcessor_QueryExpandOptionNotApplicable);
                }
            }

            if (!string.IsNullOrEmpty(this.RawSelectQueryOptionValue))
            {
                ValidateSelectIsAllowedForRequest(requestDescription);

                // Throw if $select requests have been disabled by the user
                Debug.Assert(dataService.Configuration != null, "dataService.Configuration != null");
                if (!dataService.Configuration.DataServiceBehavior.AcceptProjectionRequests)
                {
                    throw DataServiceException.CreateBadRequestError(Strings.DataServiceConfiguration_ProjectionsNotAccepted);
                }
            }

            MetadataProviderEdmModel model = dataService.Provider.GetMetadataProviderEdmModel();

            var uriParser = RequestUriProcessor.CreateUriParserWithBatchReferenceCallback(dataService, dataService.OperationContext.AbsoluteRequestUri);

            try
            {
                Debug.Assert(model.Mode == MetadataProviderEdmModelMode.Serialization, "Model expected to be in serialization mode by default");
                model.Mode  = MetadataProviderEdmModelMode.SelectAndExpandParsing;
                this.Clause = uriParser.ParseSelectAndExpand();
            }
            catch (ODataException ex)
            {
                throw new DataServiceException(400, null, ex.Message, null, ex);
            }
            finally
            {
                model.Mode = MetadataProviderEdmModelMode.Serialization;
            }

            if (this.Clause != null)
            {
                this.HasExpand = this.Clause.SelectedItems.OfType <ExpandedNavigationSelectItem>().Any();
                this.HasSelect = HasSelectedItemAtAnyLevel(this.Clause);
            }
        }
        /// <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>
        /// Initializes a new instance of the <see cref="MetadataProviderEdmFunctionImport"/> class.
        /// </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>
        internal MetadataProviderEdmFunction(MetadataProviderEdmModel model, OperationWrapper operation, string namespaceName)
            : base(model, operation, namespaceName)
        {
            this.IsComposable = DefaultIsComposable;

            // By default everything is composable except functions that return IEnumerable
            if (operation.ReturnInstanceType != null && !(typeof(IEnumerable).IsAssignableFrom(operation.ReturnInstanceType) && !typeof(IQueryable).IsAssignableFrom(operation.ReturnInstanceType)))
            {
                this.IsComposable = true;
            }
        }
        /// <summary>Initializes a new <see cref="RequestExpressionParser"/>.</summary>
        /// <param name="service">Service with data and configuration.</param>
        /// <param name="requestDescription">RequestDescription instance containing information about the current request being parsed.</param>
        internal RequestExpressionParser(IDataService service, RequestDescription requestDescription)
        {
            Debug.Assert(service != null, "service != null");
            Debug.Assert(requestDescription != null, "requestDescription != null");

            this.provider = service.Provider;

            this.model = this.provider.GetMetadataProviderEdmModel();

            this.odataUriParser = RequestUriProcessor.CreateUriParserWithBatchReferenceCallback(service, service.OperationContext.AbsoluteRequestUri);
        }
Esempio n. 9
0
        /// <summary>
        /// Reads the input request payload and returns the WCF DS value representation of it.
        /// </summary>
        /// <param name="segmentInfo">Info about the request to read.</param>
        /// <returns>The WCF DS representation of the value read.</returns>
        protected override object Read(SegmentInfo segmentInfo)
        {
            Debug.Assert(segmentInfo != null, "segmentInfo != null");
            Debug.Assert(segmentInfo.TargetKind == RequestTargetKind.Resource, "The EntityDeserializer only supports Resource target kinds.");

            ResourceType expectedResourceType = segmentInfo.TargetResourceType;

            Debug.Assert(expectedResourceType != null, "To read an entity we must know the expected resource type of the entity to read.");
            Debug.Assert(expectedResourceType.ResourceTypeKind == ResourceTypeKind.EntityType, "Only entity types can be used as types for entities.");
            IEdmEntityType expectedEntityType = (IEdmEntityType)this.GetSchemaType(expectedResourceType);

            MetadataProviderEdmModel metadataProviderEdmModel = this.Service.Provider.GetMetadataProviderEdmModel();

            Debug.Assert(metadataProviderEdmModel.Mode == MetadataProviderEdmModelMode.Serialization, "Model expected to be in serialization mode.");

            IEdmEntitySet expectedEntitySet = WebUtil.GetEntitySet(this.Service.Provider, metadataProviderEdmModel, segmentInfo.TargetResourceSet);
            ODataReader   odataReader       = this.MessageReader.CreateODataEntryReader(expectedEntitySet, expectedEntityType);

#pragma warning disable 618
            AssertReaderFormatIsExpected(this.MessageReader, ODataFormat.Atom, ODataFormat.Json);
#pragma warning restore 618

            // Read the entry and all its children into a tree. We use annotation to connect the items into the tree.
            // Note that we must cache the entire payload to preserve call order for navigation properties.
            // Due to the fact that the payload order on the wire is arbitrary, but we always set all non-navigation properties first
            // and then apply all navigation properties, we must cache the entire tree.
            ODataEntry topLevelEntry;
            try
            {
                topLevelEntry = this.ReadEntry(odataReader, segmentInfo);
            }
            catch (UriFormatException exception)
            {
                // For backward compatibility with previous released when reading ATOM we need to catch UriFormatExceptions and wrap them
                // in a bad request exception so that a 400 is reported back. In JSON we used to not do this and thus we need to continue
                // throwing the original exception which will cause a 500.
                if (this.IsAtomRequest)
                {
                    throw DataServiceException.CreateBadRequestError(Microsoft.OData.Service.Strings.Syndication_ErrorReadingEntry(exception.Message), exception);
                }

                throw;
            }

            ODataEntryAnnotation topLevelEntryAnnotation = topLevelEntry.GetAnnotation <ODataEntryAnnotation>();
            Debug.Assert(topLevelEntryAnnotation != null, "Each entry we read must have the entry annotation.");
            this.RecurseEnter();
            this.ApplyEntityProperties(segmentInfo, topLevelEntry, topLevelEntryAnnotation);
            this.RecurseLeave();

            return(topLevelEntryAnnotation);
        }
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="model">The model this instance belongs to.</param>
        /// <param name="containerName">The name of the entity container.</param>
        /// <param name="entityContainerSchemaNamespace">The namespace of the schema this entity container should be made part of during serialization.</param>
        internal MetadataProviderEdmEntityContainer(MetadataProviderEdmModel model, string containerName, string entityContainerSchemaNamespace)
        {
            Debug.Assert(model != null, "model != null");
            Debug.Assert(!string.IsNullOrEmpty(containerName), "!string.IsNullOrEmpty(containerName)");
            Debug.Assert(!string.IsNullOrEmpty(entityContainerSchemaNamespace), "!string.IsNullOrEmpty(entityContainerSchemaNamespace)");

            this.model              = model;
            this.containerName      = containerName;
            this.containerNamespace = entityContainerSchemaNamespace;

            this.entitySetCache       = new Dictionary <string, IEdmEntitySet>(StringComparer.Ordinal);
            this.operationImportCache = new Dictionary <string, List <IEdmOperationImport> >(StringComparer.Ordinal);
        }
Esempio n. 11
0
        /// <summary>Writes multiple top-level elements, possibly none.</summary>
        /// <param name="expanded">Expanded results for elements.</param>
        /// <param name="elements">Enumerator for elements to write.</param>
        protected override void WriteTopLevelElements(IExpandedResult expanded, QueryResultInfo elements)
        {
            Debug.Assert(
                !this.RequestDescription.IsSingleResult,
                "!this.RequestDescription.IsSingleResult -- otherwise WriteTopLevelElement should have been called");

            if (this.RequestDescription.LinkUri)
            {
                bool needPop = this.PushSegmentForRoot();
                this.WriteLinkCollection(elements);
                this.PopSegmentName(needPop);
            }
            else
            {
                MetadataProviderEdmModel model     = this.Service.Provider.GetMetadataProviderEdmModel();
                OperationWrapper         operation = this.RequestDescription.LastSegmentInfo.Operation;

                IEdmOperation edmOperation = model.GetRelatedOperation(operation);
                Debug.Assert(edmOperation != null, "edmOperation != null");

                IEdmCollectionTypeReference collectionType = (IEdmCollectionTypeReference)edmOperation.ReturnType;
                bool isJsonLightResponse = ContentTypeUtil.IsResponseMediaTypeJsonLight(this.Service, /*isEntryOrFeed*/ false);
                this.collectionWriter = this.writer.CreateODataCollectionWriter(isJsonLightResponse ? null : collectionType.ElementType());

                ODataCollectionStart collectionStart = new ODataCollectionStart {
                    Name = this.ComputeContainerName()
                };
                collectionStart.SetSerializationInfo(new ODataCollectionStartSerializationInfo {
                    CollectionTypeName = collectionType.FullName()
                });

                this.collectionWriter.WriteStart(collectionStart);
                while (elements.HasMoved)
                {
                    object       element      = elements.Current;
                    ResourceType resourceType = element == null ?
                                                this.RequestDescription.TargetResourceType : WebUtil.GetResourceType(this.Provider, element);
                    if (resourceType == null)
                    {
                        throw new InvalidOperationException(Microsoft.OData.Service.Strings.Serializer_UnsupportedTopLevelType(element.GetType()));
                    }

                    this.collectionWriter.WriteItem(this.GetPropertyValue(XmlConstants.XmlCollectionItemElementName, resourceType, element, false /*openProperty*/).FromODataValue());
                    elements.MoveNext();
                }

                this.collectionWriter.WriteEnd();
                this.collectionWriter.Flush();
            }
        }
Esempio n. 12
0
        /// <summary>
        /// Prepares the service's model for serialization during a $metadata request by adding versioning annotations and running validation.
        /// </summary>
        /// <param name="provider">The service's provider</param>
        /// <param name="configuration">The service's configuration</param>
        /// <returns>Returns the prepared model.</returns>
        internal static IEdmModel PrepareModelForSerialization(DataServiceProviderWrapper provider, DataServiceConfiguration configuration)
        {
            Debug.Assert(provider != null, "provider != null");
            Debug.Assert(configuration != null, "configuration != null");

            MetadataProviderEdmModel model = provider.GetMetadataProviderEdmModel();

            model.AssertCacheEmpty();

            // For computing the metadata version, we need to walk through all the types and operations.
            // This causes the model to be also completely populated and hence the metadata is loaded
            // based on the MPV on the server.
            // But there are some changes we made in 5.0 OOB release that we will display the right
            // value of Nullable attribute in $metadata for V3 and above. Since the metadata version
            // is not known, this is not correctly populated. Hence we need to compute the metadata
            // version first, and then clear the model so that it can be populated again based on the
            // the computed metadata version.
            Version minMetadataEdmSchemaVersion = model.MinMetadataEdmSchemaVersion;

            // NOTE: The below annotations on the model are only relevant for $metadata serialization.
            //       We set them every time the metadata document is written.
            Version metadataEdmSchemaVersion = provider.SchemaVersion.ToVersion();

            if (minMetadataEdmSchemaVersion > metadataEdmSchemaVersion)
            {
                metadataEdmSchemaVersion = minMetadataEdmSchemaVersion;
            }

            model.SetEdmVersion(metadataEdmSchemaVersion);

            // For Astoria, set the EDMX version of the model always to "1.0"
            model.SetEdmxVersion(edmxVersion);

            // now load the entire model.
            model.EnsureFullMetadataLoaded();

            // even though there may not be user annotations there may be an annotation for Azure key url, this must always be called
            model.AnnotationsCache.PopulateFromConfiguration(configuration);

            // If model validation is enabled, validate the model before writing.
            if (!configuration.DisableValidationOnMetadataWrite)
            {
                ValidateModel(model, metadataEdmSchemaVersion);
            }

            return(model);
        }
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="model">The model this instance belongs to.</param>
        /// <param name="container">The container this instance belongs to.</param>
        /// <param name="edmOperation">The edm operation underlying this function import.</param>
        /// <remarks>This constructor assumes that the entity set for this service operation has already be created.</remarks>
        protected internal MetadataProviderEdmOperationImport(
            MetadataProviderEdmModel model,
            MetadataProviderEdmEntityContainer container,
            MetadataProviderEdmOperation edmOperation)
        {
            Debug.Assert(model != null, "model != null");
            Debug.Assert(container != null, "container != null");
            Debug.Assert(edmOperation != null, "edmOperation != null");

            this.container    = container;
            this.model        = model;
            this.edmOperation = edmOperation;

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

            this.entitySetPath = resultSetPathExpression == null ? null : resultSetPathExpression.PathExpression;
        }
Esempio n. 14
0
        /// <summary>
        /// Creates an instance of <see cref="SelectItem"/> to represent the selection of the given property.
        /// </summary>
        /// <param name="metadataProviderEdmModel">The metadata provider-based edm model.</param>
        /// <param name="targetResourceType">The resource type the property is being selected for.</param>
        /// <param name="property">The property being selected.</param>
        /// <param name="typeSegments">Type segments seen in the path so far.</param>
        /// <returns>A new <see cref="SelectItem"/> to represent the selection of the given property.</returns>
        private static SelectItem CreatePropertySelection(MetadataProviderEdmModel metadataProviderEdmModel, ResourceType targetResourceType, ResourceProperty property, ICollection <TypeSegment> typeSegments)
        {
            var          structuredType        = (IEdmStructuredType)metadataProviderEdmModel.EnsureSchemaType(targetResourceType);
            IEdmProperty edmProperty           = structuredType.FindProperty(property.Name);
            var          edmStructuralProperty = edmProperty as IEdmStructuralProperty;

            Segment lastSegment;

            if (edmStructuralProperty != null)
            {
                lastSegment = new PropertySegment(edmStructuralProperty);
            }
            else
            {
                lastSegment = new NavigationPropertySegment((IEdmNavigationProperty)edmProperty);
            }

            var path = CreatePath(typeSegments, lastSegment);

            return(new PathSelectItem(path));
        }
Esempio n. 15
0
        /// <summary>
        /// Binds the expand paths from the requests $expand query option to the sets/types/properties from the metadata provider of the service.
        /// </summary>
        /// <param name="requestDescription">The request description.</param>
        /// <param name="dataService">The data service.</param>
        /// <param name="expandQueryOption">The value of the $expand query option.</param>
        /// <returns>The bound expand segments.</returns>
        internal static IList <IList <ExpandItem> > BindExpandSegments(RequestDescription requestDescription, IDataService dataService, string expandQueryOption)
        {
            Debug.Assert(requestDescription != null, "requestDescription != null");
            Debug.Assert(dataService != null, "dataService != null");

            if (string.IsNullOrWhiteSpace(expandQueryOption))
            {
                return(new List <IList <ExpandItem> >());
            }

            ResourceType       targetResourceType = requestDescription.TargetResourceType;
            ResourceSetWrapper targetResourceSet  = requestDescription.TargetResourceSet;

            if (targetResourceType == null || targetResourceType.ResourceTypeKind != ResourceTypeKind.EntityType || targetResourceSet == null)
            {
                throw DataServiceException.CreateBadRequestError(Strings.RequestQueryProcessor_QueryExpandOptionNotApplicable);
            }

            MetadataProviderEdmModel model      = dataService.Provider.GetMetadataProviderEdmModel();
            IEdmEntityType           targetType = (IEdmEntityType)model.EnsureSchemaType(targetResourceType);
            IEdmEntitySet            targetSet  = model.EnsureEntitySet(targetResourceSet);

            SelectExpandClause clause;

            try
            {
                model.Mode = MetadataProviderEdmModelMode.SelectAndExpandParsing;
                clause     = ODataUriParser.ParseSelectAndExpand(/*select*/ null, expandQueryOption, model, targetType, targetSet);
            }
            catch (ODataException ex)
            {
                throw new DataServiceException(400, null, ex.Message, null, ex);
            }
            finally
            {
                model.Mode = MetadataProviderEdmModelMode.Serialization;
            }

            return(new ExpandAndSelectPathExtractor(clause).ExpandPaths);
        }
Esempio n. 16
0
        /// <summary>
        /// Gets the EDM model from the service.
        /// </summary>
        /// <returns>The EDM model or null.</returns>
        private IEdmModel GetModelFromService()
        {
            Debug.Assert(this.service != null, "this.service != null");

            // DEVNOTE: Its unclear why this check for OperationContext being non-null is needed,
            // or what it has to do with the model. It was refactored from another place, and more
            // investigation is needed.
            if (this.service.OperationContext != null)
            {
                Debug.Assert(this.requestDescription != null, "this.requestDescription != null");
                bool isEntryOrFeed = this.requestDescription.TargetKind == RequestTargetKind.Resource;
                if (!ContentTypeUtil.IsResponseMediaTypeJsonLight(this.service, isEntryOrFeed))
                {
                    Debug.Assert(this.service.Provider != null, "this.service.Provider != null");
                    MetadataProviderEdmModel metadataProviderEdmModel = this.service.Provider.GetMetadataProviderEdmModel();
                    Debug.Assert(metadataProviderEdmModel.Mode == MetadataProviderEdmModelMode.Serialization, "Model expected to be in serialization mode.");
                    return(metadataProviderEdmModel);
                }
            }

            return(null);
        }
        private static MetadataProviderEdmModel CreateMetadataProviderEdmModel(DataServiceProviderSimulator metadataProvider, IDataServiceActionProvider actionProvider = null)
        {
            var dataServiceSimulator = new DataServiceSimulatorWithGetService {
                OperationContext = new DataServiceOperationContext(false, new DataServiceHost2Simulator()), ProcessingPipeline = new DataServiceProcessingPipeline()
            };

            dataServiceSimulator.OperationContext.InitializeAndCacheHeaders(dataServiceSimulator);

            var dataServiceConfiguration = new DataServiceConfiguration(metadataProvider);

            dataServiceConfiguration.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
            dataServiceConfiguration.SetServiceActionAccessRule("*", ServiceActionRights.Invoke);
            dataServiceConfiguration.DataServiceBehavior.MaxProtocolVersion = ODataProtocolVersion.V4;

            if (actionProvider != null)
            {
                dataServiceSimulator.Providers.Add(typeof(IDataServiceActionProvider), actionProvider);
            }

            DataServiceStaticConfiguration staticConfiguration = new DataServiceStaticConfiguration(dataServiceSimulator.Instance.GetType(), metadataProvider);
            IDataServiceProviderBehavior   providerBehavior    = DataServiceProviderBehavior.CustomDataServiceProviderBehavior;

            DataServiceProviderWrapper providerWrapper = new DataServiceProviderWrapper(
                new DataServiceCacheItem(
                    dataServiceConfiguration,
                    staticConfiguration),
                metadataProvider,
                metadataProvider,
                dataServiceSimulator,
                false);

            dataServiceSimulator.Provider = providerWrapper;

            var model = new MetadataProviderEdmModel(providerWrapper, new DataServiceStreamProviderWrapper(dataServiceSimulator), DataServiceActionProviderWrapper.Create(dataServiceSimulator));

            model.MetadataProvider.ProviderBehavior = providerBehavior;
            return(model);
        }
Esempio n. 18
0
        /// <summary>
        /// Binds the paths from the request's $select query option to the sets/types/properties from the metadata provider of the service.
        /// </summary>
        /// <param name="requestDescription">The request description.</param>
        /// <param name="dataService">The data service.</param>
        /// <param name="selectQueryOption">The raw value of the $select query option.</param>
        /// <returns>The bound select segments.</returns>
        internal static IList <IList <SelectItem> > BindSelectSegments(RequestDescription requestDescription, IDataService dataService, string selectQueryOption)
        {
            Debug.Assert(requestDescription != null, "requestDescription != null");
            Debug.Assert(dataService != null, "dataService != null");

            if (string.IsNullOrEmpty(selectQueryOption))
            {
                return(new List <IList <SelectItem> >());
            }

            // Throw if $select requests have been disabled by the user
            Debug.Assert(dataService.Configuration != null, "dataService.Configuration != null");
            if (!dataService.Configuration.DataServiceBehavior.AcceptProjectionRequests)
            {
                throw DataServiceException.CreateBadRequestError(Strings.DataServiceConfiguration_ProjectionsNotAccepted);
            }

            IList <IList <string> > selectPathsAsText = SplitSelect(selectQueryOption, dataService.Provider);

            Debug.Assert(selectPathsAsText != null, "selectPathsAsText != null");

            List <IList <SelectItem> > boundSegments = new List <IList <SelectItem> >(selectPathsAsText.Count);

            if (selectPathsAsText.Count == 0)
            {
                return(boundSegments);
            }

            ValidateSelectIsAllowedForRequest(requestDescription);

            MetadataProviderEdmModel metadataProviderEdmModel = dataService.Provider.GetMetadataProviderEdmModel();

            for (int i = selectPathsAsText.Count - 1; i >= 0; i--)
            {
                IList <string>    path             = selectPathsAsText[i];
                List <SelectItem> boundSegmentPath = new List <SelectItem>(path.Count);
                boundSegments.Add(boundSegmentPath);

                ResourceType       targetResourceType = requestDescription.TargetResourceType;
                ResourceSetWrapper targetResourceSet  = requestDescription.TargetResourceSet;

                // if we get to here, we're building a partial selection
                List <TypeSegment> typeSegments   = new List <TypeSegment>();
                bool previousSegmentIsTypeSegment = false;
                for (int j = 0; j < path.Count; j++)
                {
                    string pathSegment     = path[j];
                    bool   lastPathSegment = (j == path.Count - 1);

                    // '*' is special, it means "Project all immediate properties on this level."
                    if (pathSegment == "*")
                    {
                        Debug.Assert(lastPathSegment, "A wildcard select segment must be the last one. This should have been checked already when splitting appart the paths.");
                        boundSegmentPath.Add(CreateWildcardSelection());
                        continue;
                    }

                    bool   nameIsContainerQualified;
                    string nameFromContainerQualifiedName = dataService.Provider.GetNameFromContainerQualifiedName(pathSegment, out nameIsContainerQualified);
                    if (nameFromContainerQualifiedName == "*")
                    {
                        Debug.Assert(lastPathSegment, "A wildcard select segment must be the last one.  This should have been checked already when splitting appart the paths.");
                        Debug.Assert(nameIsContainerQualified, "nameIsContainerQualified == true");
                        boundSegmentPath.Add(CreateContainerQualifiedWildcardSelection(metadataProviderEdmModel));
                        continue;
                    }

                    ResourceProperty property = targetResourceType.TryResolvePropertyName(pathSegment);
                    if (property == null)
                    {
                        ResourceType resolvedResourceType = WebUtil.ResolveTypeIdentifier(dataService.Provider, pathSegment, targetResourceType, previousSegmentIsTypeSegment);
                        if (resolvedResourceType != null)
                        {
                            previousSegmentIsTypeSegment = true;
                            if (lastPathSegment)
                            {
                                throw DataServiceException.CreateBadRequestError(Strings.RequestQueryProcessor_QueryParametersPathCannotEndInTypeIdentifier(XmlConstants.HttpQueryStringSelect, resolvedResourceType.FullName));
                            }

                            targetResourceType = resolvedResourceType;

                            // Whenever we encounter the type segment, we need to only verify that the MPV is set to 3.0 or higher.
                            // There is no need to check for request DSV, request MinDSV or request MaxDSV since there are no protocol changes in
                            // the payload for uri's with type identifier.
                            requestDescription.VerifyProtocolVersion(VersionUtil.Version3Dot0, dataService);

                            IEdmSchemaType edmType     = metadataProviderEdmModel.EnsureSchemaType(targetResourceType);
                            TypeSegment    typeSegment = new TypeSegment(edmType);
                            typeSegments.Add(typeSegment);
                            continue;
                        }

                        previousSegmentIsTypeSegment = false;

                        // If the currentResourceType is an open type, we require the service action name to be fully qualified or else we treat it as an open property name.
                        if (!targetResourceType.IsOpenType || nameIsContainerQualified)
                        {
                            // Note that if the service does not implement IDataServiceActionProvider and the MaxProtocolVersion < V3,
                            // GetActionsBoundToAnyTypeInResourceSet() would simply return an empty ServiceOperationWrapper collection.
                            Debug.Assert(dataService.ActionProvider != null, "dataService.ActionProvider != null");
                            IEnumerable <OperationWrapper> allOperationsInSet     = dataService.ActionProvider.GetActionsBoundToAnyTypeInResourceSet(targetResourceSet);
                            List <OperationWrapper>        selectedServiceActions = allOperationsInSet.Where(o => o.Name == nameFromContainerQualifiedName).ToList();

                            if (selectedServiceActions.Count > 0)
                            {
                                if (!lastPathSegment)
                                {
                                    throw DataServiceException.CreateBadRequestError(Strings.RequestQueryProcessor_ServiceActionMustBeLastSegmentInSelect(pathSegment));
                                }

                                boundSegmentPath.Add(CreateOperationSelection(metadataProviderEdmModel, selectedServiceActions, typeSegments));
                                continue;
                            }
                        }

                        if (!targetResourceType.IsOpenType)
                        {
                            throw DataServiceException.CreateSyntaxError(Strings.RequestUriProcessor_PropertyNotFound(targetResourceType.FullName, pathSegment));
                        }

                        if (!lastPathSegment)
                        {
                            // Open navigation properties are not supported on OpenTypes.
                            throw DataServiceException.CreateBadRequestError(Strings.OpenNavigationPropertiesNotSupportedOnOpenTypes(pathSegment));
                        }

                        boundSegmentPath.Add(CreateOpenPropertySelection(pathSegment, typeSegments));
                    }
                    else
                    {
                        previousSegmentIsTypeSegment = false;

                        ValidateSelectedProperty(targetResourceType, property, lastPathSegment);

                        boundSegmentPath.Add(CreatePropertySelection(metadataProviderEdmModel, targetResourceType, property, typeSegments));

                        if (property.TypeKind == ResourceTypeKind.EntityType)
                        {
                            targetResourceSet  = dataService.Provider.GetResourceSet(targetResourceSet, targetResourceType, property);
                            targetResourceType = property.ResourceType;
                        }
                    }
                }

                // Note that this check is also covering cases where a type segment is followed by a wildcard.
                if (previousSegmentIsTypeSegment)
                {
                    throw DataServiceException.CreateBadRequestError(Strings.RequestQueryProcessor_QueryParametersPathCannotEndInTypeIdentifier(XmlConstants.HttpQueryStringSelect, targetResourceType.FullName));
                }
            }

            return(boundSegments);
        }
Esempio n. 19
0
 /// <summary>
 /// Creates an instance of <see cref="SelectItem"/> to represent the selection of an set of operations.
 /// </summary>
 /// <param name="metadataProviderEdmModel">The metadata provider-based edm model.</param>
 /// <param name="selectedServiceActions">The operations being selected.</param>
 /// <param name="typeSegments">Type segments seen in the path so far.</param>
 /// <returns>A new <see cref="SelectItem"/> to represent the selection of the operations.</returns>
 private static SelectItem CreateOperationSelection(MetadataProviderEdmModel metadataProviderEdmModel, IEnumerable <OperationWrapper> selectedServiceActions, ICollection <TypeSegment> typeSegments)
 {
     return(new PathSelectItem(CreatePath(typeSegments, new OperationSegment(selectedServiceActions.Select(a => metadataProviderEdmModel.EnsureDefaultEntityContainer().EnsureFunctionImport(a)).ToList()))));
 }
Esempio n. 20
0
 /// <summary>
 /// Creates a new instance of <see cref="ContainerQualifiedWildcardSelectItem"/>.
 /// </summary>
 /// <param name="metadataProviderEdmModel">The metadata provider-based edm model.</param>
 /// <returns>A new instance of <see cref="ContainerQualifiedWildcardSelectItem"/>.</returns>
 private static ContainerQualifiedWildcardSelectItem CreateContainerQualifiedWildcardSelection(MetadataProviderEdmModel metadataProviderEdmModel)
 {
     return(new ContainerQualifiedWildcardSelectItem(metadataProviderEdmModel.EnsureDefaultEntityContainer()));
 }
Esempio n. 21
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();
        }