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) { }
/// <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; }
/// <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; }
/// <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); }
/// <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); }
/// <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(); } }
/// <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; }
/// <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)); }
/// <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); }
/// <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); }
/// <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); }
/// <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())))); }
/// <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())); }
/// <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(); }