/// <summary> /// Applies the values of a nested <paramref name="feed"/> to the collection /// <paramref name="property"/> of the specified <paramref name="entry"/>. /// </summary> /// <param name="entry">Entry with collection to be modified.</param> /// <param name="property">Collection property on the entry.</param> /// <param name="feed">Values to apply onto the collection.</param> /// <param name="includeLinks">Whether links that are expanded should be materialized.</param> private void ApplyFeedToCollection( MaterializerEntry entry, ClientPropertyAnnotation property, ODataResourceSet feed, bool includeLinks) { Debug.Assert(entry.Entry != null, "entry != null"); Debug.Assert(property != null, "property != null"); Debug.Assert(feed != null, "feed != null"); ClientEdmModel edmModel = this.MaterializerContext.Model; ClientTypeAnnotation collectionType = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(property.ResourceSetItemType)); IEnumerable <ODataResource> entries = MaterializerFeed.GetFeed(feed).Entries; foreach (ODataResource feedEntry in entries) { this.Materialize(MaterializerEntry.GetEntry(feedEntry), collectionType.ElementType, includeLinks); } ProjectionPlan continuationPlan = includeLinks ? ODataEntityMaterializer.CreatePlanForDirectMaterialization(property.ResourceSetItemType) : ODataEntityMaterializer.CreatePlanForShallowMaterialization(property.ResourceSetItemType); this.ApplyItemsToCollection( entry, property, entries.Select(e => MaterializerEntry.GetEntry(e).ResolvedObject), feed.NextPageLink, continuationPlan, false); }
/// <summary>constructor</summary> /// <param name="entity">entity</param> /// <param name="propertyName">name of collection or reference property to load</param> /// <param name="context">Originating context</param> /// <param name="request">Originating WebRequest</param> /// <param name="callback">user callback</param> /// <param name="state">user state</param> /// <param name="dataServiceRequest">request object.</param> /// <param name="plan">Projection plan for materialization; possibly null.</param> /// <param name="isContinuation">Whether this request is a continuation request.</param> internal LoadPropertyResult(object entity, string propertyName, DataServiceContext context, ODataRequestMessageWrapper request, AsyncCallback callback, object state, DataServiceRequest dataServiceRequest, ProjectionPlan plan, bool isContinuation) : base(context, Util.LoadPropertyMethodName, dataServiceRequest, request, new RequestInfo(context, isContinuation), callback, state) { this.entity = entity; this.propertyName = propertyName; this.plan = plan; }
internal static object ProjectionInitializeEntity(ODataEntityMaterializer materializer, MaterializerEntry entry, Type expectedType, Type resultType, string[] properties, Func <object, object, Type, object>[] propertyValues) { if (entry.Entry == null) { throw new NullReferenceException(System.Data.Services.Client.Strings.AtomMaterializer_EntryToInitializeIsNull(resultType.FullName)); } if (!entry.EntityHasBeenResolved) { ProjectionEnsureEntryAvailableOfType(materializer, entry, resultType); } else if (!resultType.IsAssignableFrom(entry.ActualType.ElementType)) { throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomMaterializer_ProjectEntityTypeMismatch(resultType.FullName, entry.ActualType.ElementType.FullName, entry.Entry.Id)); } object resolvedObject = entry.ResolvedObject; for (int i = 0; i < properties.Length; i++) { StreamDescriptor descriptor; string propertyName = properties[i]; ClientPropertyAnnotation annotation = entry.ActualType.GetProperty(propertyName, materializer.ResponseInfo.IgnoreMissingProperties); object target = propertyValues[i](materializer, entry.Entry, expectedType); ODataProperty property = (from p in entry.Entry.Properties where p.Name == propertyName select p).FirstOrDefault <ODataProperty>(); if ((((((property == null) && (entry.NavigationLinks != null)) ? (from l in entry.NavigationLinks where l.Name == propertyName select l).FirstOrDefault <ODataNavigationLink>() : null) != null) || (property != null)) || entry.EntityDescriptor.TryGetNamedStreamInfo(propertyName, out descriptor)) { if (entry.ShouldUpdateFromPayload && (annotation.EdmProperty.Type.TypeKind() == EdmTypeKind.Entity)) { materializer.Log.SetLink(entry, annotation.PropertyName, target); } if (entry.ShouldUpdateFromPayload) { if (!annotation.IsEntityCollection) { if (!annotation.IsPrimitiveOrComplexCollection) { annotation.SetValue(resolvedObject, target, annotation.PropertyName, false); } } else { IEnumerable list = (IEnumerable)target; DataServiceQueryContinuation continuation = materializer.nextLinkTable[list]; Uri nextLink = (continuation == null) ? null : continuation.NextLinkUri; ProjectionPlan plan = (continuation == null) ? null : continuation.Plan; materializer.MergeLists(entry, annotation, list, nextLink, plan); } } else if (annotation.IsEntityCollection) { materializer.FoundNextLinkForUnmodifiedCollection(annotation.GetValue(entry.ResolvedObject) as IEnumerable); } } } return(resolvedObject); }
/// <summary>Create a request for a specific Uri</summary> /// <param name="requestUri">The URI for the request.</param> /// <param name="queryComponents">The query components for the request</param> /// <param name="plan">Projection plan to reuse (possibly null).</param> internal DataServiceRequest(Uri requestUri, QueryComponents queryComponents, ProjectionPlan plan) : this(requestUri) { Debug.Assert(requestUri != null, "requestUri != null"); Debug.Assert(queryComponents != null, "queryComponents != null"); this.queryComponents = queryComponents; this.plan = plan; }
private void FoundNextLinkForCollection(IEnumerable collection, Uri link, ProjectionPlan plan) { if ((collection != null) && !base.nextLinkTable.ContainsKey(collection)) { DataServiceQueryContinuation continuation = DataServiceQueryContinuation.Create(link, plan); base.nextLinkTable.Add(collection, continuation); Util.SetNextLinkForCollection(collection, continuation); } }
/// <summary>Initializes a new <see cref="DataServiceQueryContinuation"/> instance.</summary> /// <param name="nextLinkUri">URI to next page of data.</param> /// <param name="plan">Projection plan for results of next page.</param> internal DataServiceQueryContinuation(Uri nextLinkUri, ProjectionPlan plan) { Debug.Assert(nextLinkUri != null, "nextLinkUri != null"); Debug.Assert(plan != null, "plan != null"); this.nextLinkUri = nextLinkUri; this.plan = plan; #if DEBUG this.deserializing = false; #endif }
/// <summary>Records the fact that a rel='next' link was found for the specified <paramref name="collection"/>.</summary> /// <param name="collection">Collection to add link to.</param> /// <param name="link">Link (possibly null).</param> /// <param name="plan">Projection plan for the collection (null allowed only if link is null).</param> internal void FoundNextLinkForCollection(IEnumerable collection, Uri link, ProjectionPlan plan) { Debug.Assert(plan != null || link == null, "plan != null || link == null"); if (collection != null && !this.nextLinkTable.ContainsKey(collection)) { DataServiceQueryContinuation continuation = DataServiceQueryContinuation.Create(link, plan); this.nextLinkTable.Add(collection, continuation); Util.SetNextLinkForCollection(collection, continuation); } }
private static ProjectionPlan CreatePlan(QueryComponents queryComponents) { LambdaExpression projection = queryComponents.Projection; if (projection == null) { return(CreatePlanForDirectMaterialization(queryComponents.LastSegmentType)); } ProjectionPlan plan = ProjectionPlanCompiler.CompilePlan(projection, queryComponents.NormalizerRewrites); plan.LastSegmentType = queryComponents.LastSegmentType; return(plan); }
/// <summary> /// Initializes a new instance of the <see cref="ODataReaderEntityMaterializer" /> class. /// </summary> /// <param name="odataMessageReader">The odata message reader.</param> /// <param name="reader">The reader.</param> /// <param name="materializerContext">The materializer context.</param> /// <param name="entityTrackingAdapter">The entity tracking adapter.</param> /// <param name="queryComponents">The query components.</param> /// <param name="expectedType">The expected type.</param> /// <param name="materializeEntryPlan">The materialize entry plan.</param> public ODataReaderEntityMaterializer( ODataMessageReader odataMessageReader, ODataReaderWrapper reader, IODataMaterializerContext materializerContext, EntityTrackingAdapter entityTrackingAdapter, QueryComponents queryComponents, Type expectedType, ProjectionPlan materializeEntryPlan) : base(materializerContext, entityTrackingAdapter, queryComponents, expectedType, materializeEntryPlan) { this.messageReader = odataMessageReader; this.feedEntryAdapter = new FeedAndEntryMaterializerAdapter(odataMessageReader, reader, materializerContext.Model, entityTrackingAdapter.MergeOption); }
/// <summary> /// Initializes a new instance of the <see cref="ODataEntriesEntityMaterializer" /> class. /// </summary> /// <param name="entries">The entries.</param> /// <param name="materializerContext">The materializer context.</param> /// <param name="entityTrackingAdapter">The entity tracking adapter.</param> /// <param name="queryComponents">The query components.</param> /// <param name="expectedType">The expected type.</param> /// <param name="materializeEntryPlan">The materialize entry plan.</param> /// <param name="format">The format.</param> public ODataEntriesEntityMaterializer( IEnumerable <ODataEntry> entries, IODataMaterializerContext materializerContext, EntityTrackingAdapter entityTrackingAdapter, QueryComponents queryComponents, Type expectedType, ProjectionPlan materializeEntryPlan, ODataFormat format) : base(materializerContext, entityTrackingAdapter, queryComponents, expectedType, materializeEntryPlan) { this.format = format; this.feedEntries = entries.GetEnumerator(); }
/// <summary> /// Initializes a new instance of the <see cref="ODataLoadNavigationPropertyMaterializer" /> class. /// </summary> /// <param name="odataMessageReader">The odata message reader.</param> /// <param name="reader">The reader.</param> /// <param name="materializerContext">The materializer context.</param> /// <param name="entityTrackingAdapter">The entity tracking adapter.</param> /// <param name="queryComponents">The query components.</param> /// <param name="expectedType">The expected type.</param> /// <param name="materializeEntryPlan">The materialize entry plan.</param> /// <param name="responseInfo">LoadProperty Response Info object.</param> public ODataLoadNavigationPropertyMaterializer( ODataMessageReader odataMessageReader, ODataReaderWrapper reader, IODataMaterializerContext materializerContext, EntityTrackingAdapter entityTrackingAdapter, QueryComponents queryComponents, Type expectedType, ProjectionPlan materializeEntryPlan, LoadPropertyResponseInfo responseInfo) : base(odataMessageReader, reader, materializerContext, entityTrackingAdapter, queryComponents, expectedType, materializeEntryPlan) { this.responseInfo = responseInfo; this.items = new List <object>(); }
public void Continuation_Creates_Incorrect_DataServiceVersion() { // Regression test for:Client always sends DSV=2.0 when following a continuation token ProjectionPlan plan = new ProjectionPlan() { LastSegmentType = typeof(int), ProjectedType = typeof(int) }; var continuationToken = DataServiceQueryContinuation.Create(new Uri("http://localhost/Set?$skiptoken='Me'"), plan); QueryComponents queryComponents = continuationToken.CreateQueryComponents(); Assert.AreSame(queryComponents.Version, Util.ODataVersionEmpty, "OData-Version of query components should be empty for Continuation token"); }
/// <summary>Creates a new <see cref="DataServiceQueryContinuation"/> instance.</summary> /// <param name="nextLinkUri">Link to next page of data (possibly null).</param> /// <param name="plan">Plan to materialize the data (only null if nextLinkUri is null).</param> /// <returns>A new continuation object; null if nextLinkUri is null.</returns> internal static DataServiceQueryContinuation Create(Uri nextLinkUri, ProjectionPlan plan) { Debug.Assert(plan != null || nextLinkUri == null, "plan != null || nextLinkUri == null"); if (nextLinkUri == null) { return(null); } var constructors = typeof(DataServiceQueryContinuation <>).MakeGenericType(plan.ProjectedType).GetInstanceConstructors(false /*isPublic*/); object result = Util.ConstructorInvoke(constructors.Single(), new object[] { nextLinkUri, plan }); return((DataServiceQueryContinuation)result); }
private void ApplyFeedToCollection(MaterializerEntry entry, ClientPropertyAnnotation property, ODataFeed feed, bool includeLinks) { ClientEdmModel model = ClientEdmModel.GetModel(base.ResponseInfo.MaxProtocolVersion); ClientTypeAnnotation clientTypeAnnotation = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(property.EntityCollectionItemType)); IEnumerable <ODataEntry> entries = MaterializerFeed.GetFeed(feed).Entries; foreach (ODataEntry entry2 in entries) { this.Materialize(MaterializerEntry.GetEntry(entry2), clientTypeAnnotation.ElementType, includeLinks); } ProjectionPlan continuationPlan = includeLinks ? CreatePlanForDirectMaterialization(property.EntityCollectionItemType) : CreatePlanForShallowMaterialization(property.EntityCollectionItemType); this.ApplyItemsToCollection(entry, property, from e in entries select MaterializerEntry.GetEntry(e).ResolvedObject, feed.NextPageLink, continuationPlan); }
/// <summary> /// Populates the collection property on the entry's resolved object with the given items enumerator. /// </summary> /// <param name="entry">Entry with collection to be modified.</param> /// <param name="property">Collection property on the entry.</param> /// <param name="items">Values to apply onto the collection.</param> /// <param name="nextLink">Next link for collection continuation.</param> /// <param name="continuationPlan">Projection plan for collection continuation.</param> /// <returns>Collection instance that was populated.</returns> private object PopulateCollectionProperty( MaterializerEntry entry, ClientPropertyAnnotation property, IEnumerable <object> items, Uri nextLink, ProjectionPlan continuationPlan) { Debug.Assert(entry.Entry != null || entry.ForLoadProperty, "ODataResource should be non-null except for LoadProperty"); Debug.Assert(property != null, "property != null"); Debug.Assert(items != null, "items != null"); object collection = null; ClientEdmModel edmModel = this.MaterializerContext.Model; ClientTypeAnnotation collectionType = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(property.ResourceSetItemType)); if (entry.ShouldUpdateFromPayload) { collection = this.GetOrCreateCollectionProperty(entry.ResolvedObject, property, entry.ForLoadProperty); foreach (object item in items) { // Validate that item can be inserted into collection. ValidateCollectionElementTypeIsItemType(item.GetType(), collectionType.ElementType); property.SetValue(collection, item, property.PropertyName, true /* allowAdd? */); this.EntityTrackingAdapter.MaterializationLog.AddedLink(entry, property.PropertyName, item); } this.FoundNextLinkForCollection(collection as IEnumerable, nextLink, continuationPlan); } else { Debug.Assert(!entry.ForLoadProperty, "LoadProperty should always have ShouldUpdateForPayload set to true."); foreach (object item in items) { // Validate that item can be inserted into collection. ValidateCollectionElementTypeIsItemType(item.GetType(), collectionType.ElementType); } this.FoundNextLinkForUnmodifiedCollection(property.GetValue(entry.ResolvedObject) as IEnumerable); } return(collection); }
internal static IEnumerable ProjectionSelect(ODataEntityMaterializer materializer, MaterializerEntry entry, Type expectedType, Type resultType, ProjectionPath path, Func <object, object, Type, object> selector) { ClientEdmModel model = ClientEdmModel.GetModel(materializer.ResponseInfo.MaxProtocolVersion); ClientTypeAnnotation clientTypeAnnotation = entry.ActualType ?? model.GetClientTypeAnnotation(model.GetOrCreateEdmType(expectedType)); IEnumerable enumerable = (IEnumerable)Util.ActivatorCreateInstance(typeof(List <>).MakeGenericType(new Type[] { resultType }), new object[0]); MaterializerNavigationLink link = null; ClientPropertyAnnotation property = null; for (int i = 0; i < path.Count; i++) { ProjectionPathSegment segment = path[i]; if (segment.SourceTypeAs != null) { clientTypeAnnotation = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(segment.SourceTypeAs)); } if (segment.Member != null) { string member = segment.Member; property = clientTypeAnnotation.GetProperty(member, false); link = GetPropertyOrThrow(entry.NavigationLinks, member, entry.Id); if (link.Entry != null) { entry = link.Entry; clientTypeAnnotation = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(property.PropertyType)); } } } ValidatePropertyMatch(property, link.Link); MaterializerFeed feed = MaterializerFeed.GetFeed(link.Feed); Action <object, object> addToCollectionDelegate = ODataMaterializer.GetAddToCollectionDelegate(enumerable.GetType()); foreach (ODataEntry entry2 in feed.Entries) { object obj2 = selector(materializer, entry2, property.EntityCollectionItemType); addToCollectionDelegate(enumerable, obj2); } ProjectionPlan plan = new ProjectionPlan { LastSegmentType = property.EntityCollectionItemType, Plan = selector, ProjectedType = resultType }; materializer.FoundNextLinkForCollection(enumerable, feed.NextPageLink, plan); return(enumerable); }
/// <summary> /// Processes the result for successful request and produces the actual result of the request. /// </summary> /// <typeparam name="TElement">Element type of the result.</typeparam> /// <param name="plan">The plan to use for the projection, if available in precompiled form.</param> /// <returns>A instance of QueryResponseResult created on top of of the request.</returns> internal QueryOperationResponse <TElement> ProcessResult <TElement>(ProjectionPlan plan) { Debug.Assert(this.responseInfo != null, "The request didn't complete yet, we don't have a response info for it."); MaterializeAtom materializeAtom = this.CreateMaterializer(plan, this.ServiceRequest.PayloadKind); var response = this.GetResponse <TElement>(materializeAtom); // When query feed, the instance annotation can be materialized only when enumerating the feed. // So we register this action which will be called when enumerating the feed. materializeAtom.SetInstanceAnnotations = (instanceAnnotations) => { if (!this.responseInfo.Context.InstanceAnnotations.ContainsKey(response) && instanceAnnotations != null && instanceAnnotations.Count > 0) { this.responseInfo.Context.InstanceAnnotations.Add(response, instanceAnnotations); } }; return(response); }
/// <summary> /// Create materializer on top of response stream /// </summary> /// <param name="plan">Precompiled projection plan (possibly null).</param> /// <returns>A materializer instance ready to deserialize the result</returns> internal MaterializeAtom GetMaterializer(ProjectionPlan plan) { Debug.Assert(this.IsCompletedInternally, "request hasn't completed yet"); MaterializeAtom materializer; if (HttpStatusCode.NoContent != this.StatusCode) { Debug.Assert(this.responseInfo != null, "The request didn't complete yet, we don't have a response info for it."); materializer = this.CreateMaterializer(plan, ODataPayloadKind.Unsupported); } else { materializer = MaterializeAtom.EmptyResults; } return(materializer); }
/// <summary> /// get an enumerable materializes the objects the response /// </summary> /// <param name="responseInfo">context</param> /// <param name="queryComponents">query components</param> /// <param name="plan">Projection plan (if compiled in an earlier query).</param> /// <param name="contentType">contentType</param> /// <param name="message">the message</param> /// <param name="expectedPayloadKind">expected payload kind.</param> /// <returns>atom materializer</returns> internal static MaterializeAtom Materialize( ResponseInfo responseInfo, QueryComponents queryComponents, ProjectionPlan plan, string contentType, IODataResponseMessage message, ODataPayloadKind expectedPayloadKind) { Debug.Assert(queryComponents != null, "querycomponents"); Debug.Assert(message != null, "message"); // If there is no content (For e.g. /Customers(1)/BestFriend is null), we need to return empty results. if (message.StatusCode == (int)HttpStatusCode.NoContent || String.IsNullOrEmpty(contentType)) { return(MaterializeAtom.EmptyResults); } return(new MaterializeAtom(responseInfo, queryComponents, plan, message, expectedPayloadKind)); }
#pragma warning restore 649 #endif #endregion Private fields /// <summary> /// constructor /// </summary> /// <param name="responseInfo">originating context</param> /// <param name="queryComponents">Query components (projection, expected type)</param> /// <param name="plan">Projection plan (if compiled in an earlier query).</param> /// <param name="responseMessage">responseMessage</param> /// <param name="payloadKind">The kind of the payload to materialize.</param> internal MaterializeAtom( ResponseInfo responseInfo, QueryComponents queryComponents, ProjectionPlan plan, IODataResponseMessage responseMessage, ODataPayloadKind payloadKind) { Debug.Assert(queryComponents != null, "queryComponents != null"); this.responseInfo = responseInfo; this.elementType = queryComponents.LastSegmentType; this.expectingPrimitiveValue = PrimitiveType.IsKnownNullableType(elementType); Debug.Assert(responseMessage != null, "Response message is null! Did you mean to use Materializer.ResultsWrapper/EmptyResults?"); Type implementationType; Type materializerType = GetTypeForMaterializer(this.expectingPrimitiveValue, this.elementType, responseInfo.Model, out implementationType); this.materializer = ODataMaterializer.CreateMaterializerForMessage(responseMessage, responseInfo, materializerType, queryComponents, plan, payloadKind); }
/// <summary> /// Creates an instance of <see cref="MaterializeAtom"/> for the given plan. /// </summary> /// <param name="plan">The projection plan.</param> /// <param name="payloadKind">expected payload kind.</param> /// <returns>A new materializer instance</returns> private MaterializeAtom CreateMaterializer(ProjectionPlan plan, ODataPayloadKind payloadKind) { QueryComponents queryComponents = this.ServiceRequest.QueryComponents(this.responseInfo.Model); // In V2, in projection path, we did not check for assignability between the expected type and the type returned by the type resolver. if (plan != null || queryComponents.Projection != null) { this.RequestInfo.TypeResolver.IsProjectionRequest(); } var responseMessageWrapper = new HttpWebResponseMessage( new HeaderCollection(this.responseMessage), this.responseMessage.StatusCode, this.GetResponseStream); return(DataServiceRequest.Materialize( this.responseInfo, queryComponents, plan, this.ContentType, responseMessageWrapper, payloadKind)); }
private void MergeLists(MaterializerEntry entry, ClientPropertyAnnotation property, IEnumerable list, Uri nextLink, ProjectionPlan plan) { if ((entry.ShouldUpdateFromPayload && (property.NullablePropertyType == list.GetType())) && (property.GetValue(entry.ResolvedObject) == null)) { property.SetValue(entry.ResolvedObject, list, property.PropertyName, false); this.FoundNextLinkForCollection(list, nextLink, plan); foreach (object obj2 in list) { this.log.AddedLink(entry, property.PropertyName, obj2); } } else { this.ApplyItemsToCollection(entry, property, list, nextLink, plan); } }
public static ODataMaterializer CreateMaterializerForMessage(IODataResponseMessage responseMessage, System.Data.Services.Client.ResponseInfo responseInfo, Type materializerType, QueryComponents queryComponents, ProjectionPlan plan, ODataPayloadKind payloadKind) { ODataMaterializer materializer2; bool projectionQuery = (plan != null) || (queryComponents.Projection != null); ODataMessageReader messageReader = CreateODataMessageReader(responseMessage, responseInfo, projectionQuery, ref payloadKind); IEdmType expectedType = null; try { ODataMaterializer materializer; if (materializerType != typeof(object)) { expectedType = ClientEdmModel.GetModel(responseInfo.MaxProtocolVersion).GetOrCreateEdmType(materializerType); } if ((payloadKind == ODataPayloadKind.Entry) || (payloadKind == ODataPayloadKind.Feed)) { if ((expectedType != null) && (expectedType.TypeKind != EdmTypeKind.Entity)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.AtomMaterializer_InvalidNonEntityType(materializerType.FullName)); } ODataReader reader = CreateODataReader(messageReader, payloadKind, expectedType, responseInfo.MaxProtocolVersion); materializer = new ODataReaderEntityMaterializer(messageReader, reader, responseInfo, queryComponents, materializerType, plan); } else { switch (payloadKind) { case ODataPayloadKind.Property: if ((expectedType != null) && (expectedType.TypeKind == EdmTypeKind.Entity)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.AtomMaterializer_InvalidEntityType(materializerType.FullName)); } break; case ODataPayloadKind.EntityReferenceLink: case ODataPayloadKind.EntityReferenceLinks: materializer = new ODataLinksMaterializer(messageReader, responseInfo, materializerType, queryComponents.SingleResult); goto Label_013A; case ODataPayloadKind.Value: materializer = new ODataValueMaterializer(messageReader, responseInfo, materializerType, queryComponents.SingleResult); goto Label_013A; case ODataPayloadKind.BinaryValue: case ODataPayloadKind.Collection: case ODataPayloadKind.ServiceDocument: case ODataPayloadKind.MetadataDocument: goto Label_0129; case ODataPayloadKind.Error: { ODataError error = messageReader.ReadError(); throw new ODataErrorException(error.Message, error); } default: goto Label_0129; } materializer = new ODataPropertyMaterializer(messageReader, responseInfo, materializerType, queryComponents.SingleResult); } goto Label_013A; Label_0129: throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.AtomMaterializer_InvalidResponsePayload(responseInfo.DataNamespace)); Label_013A: materializer2 = materializer; } catch (Exception exception) { if (CommonUtil.IsCatchableExceptionType(exception)) { messageReader.Dispose(); } throw; } return(materializer2); }
/// <summary> /// Applies the values of the <paramref name="items"/> enumeration to the /// <paramref name="property"/> of the specified <paramref name="entry"/>. /// </summary> /// <param name="entry">Entry with collection to be modified.</param> /// <param name="property">Collection property on the entry.</param> /// <param name="items">Values to apply onto the collection.</param> /// <param name="nextLink">Next link for collection continuation.</param> /// <param name="continuationPlan">Projection plan for collection continuation.</param> /// <param name="isContinuation">Whether this is a continuation request.</param> internal void ApplyItemsToCollection( MaterializerEntry entry, ClientPropertyAnnotation property, IEnumerable items, Uri nextLink, ProjectionPlan continuationPlan, bool isContinuation) { Debug.Assert(entry.Entry != null || entry.ForLoadProperty, "ODataResource should be non-null except for LoadProperty"); Debug.Assert(property != null, "property != null"); Debug.Assert(items != null, "items != null"); IEnumerable <object> itemsEnumerable = ODataEntityMaterializer.EnumerateAsElementType <object>(items); // Populate the collection property with items collection. object collection = this.PopulateCollectionProperty(entry, property, itemsEnumerable, nextLink, continuationPlan); // Get collection of all non-linked elements in collection and remove them except for the ones that were obtained from the response. if (this.EntityTrackingAdapter.MergeOption == MergeOption.OverwriteChanges || this.EntityTrackingAdapter.MergeOption == MergeOption.PreserveChanges) { var linkedItemsInCollection = this.EntityTrackingAdapter .EntityTracker .GetLinks(entry.ResolvedObject, property.PropertyName) .Select(l => new { l.Target, l.IsModified }); if (collection != null && !property.IsDictionary) { var nonLinkedNonReceivedItemsInCollection = ODataEntityMaterializer.EnumerateAsElementType <object>((IEnumerable)collection) .Except(linkedItemsInCollection.Select(i => i.Target)) .Except(itemsEnumerable).ToArray(); // Since no link exists, we just remove the item from the collection foreach (var item in nonLinkedNonReceivedItemsInCollection) { property.RemoveValue(collection, item); } } // When the first time a property or collection is being loaded, we remove all items other than the ones that we receive. if (!isContinuation) { IEnumerable <object> itemsToRemove; if (this.EntityTrackingAdapter.MergeOption == MergeOption.OverwriteChanges) { itemsToRemove = linkedItemsInCollection.Select(i => i.Target); } else { Debug.Assert( this.EntityTrackingAdapter.MergeOption == MergeOption.PreserveChanges, "this.EntityTrackingAdapter.MergeOption == MergeOption.PreserveChanges"); itemsToRemove = linkedItemsInCollection .Where(i => !i.IsModified) .Select(i => i.Target); } itemsToRemove = itemsToRemove.Except(itemsEnumerable); foreach (var item in itemsToRemove) { if (collection != null) { property.RemoveValue(collection, item); } this.EntityTrackingAdapter.MaterializationLog.RemovedLink(entry, property.PropertyName, item); } } } }
/// <summary> /// Creates an <see cref="ODataMaterializer"/> for a response. /// </summary> /// <param name="responseMessage">The response message.</param> /// <param name="responseInfo">The response context.</param> /// <param name="materializerType">The type to materialize.</param> /// <param name="queryComponents">The query components for the request.</param> /// <param name="plan">The projection plan.</param> /// <param name="payloadKind">expected payload kind.</param> /// <returns>A materializer specialized for the given response.</returns> public static ODataMaterializer CreateMaterializerForMessage( IODataResponseMessage responseMessage, ResponseInfo responseInfo, Type materializerType, QueryComponents queryComponents, ProjectionPlan plan, ODataPayloadKind payloadKind) { ODataMessageReader messageReader = CreateODataMessageReader(responseMessage, responseInfo, ref payloadKind); ODataMaterializer result; IEdmType edmType = null; try { ODataMaterializerContext materializerContext = new ODataMaterializerContext(responseInfo); // Since in V1/V2, astoria client allowed Execute<object> and depended on the typeresolver or the wire type name // to get the clr type to materialize. Hence if we see the materializer type as object, we should set the edmtype // to null, since there is no expected type. if (materializerType != typeof(System.Object)) { edmType = responseInfo.TypeResolver.ResolveExpectedTypeForReading(materializerType); } if (payloadKind == ODataPayloadKind.Property && edmType != null) { if (edmType.TypeKind.IsStructured()) { payloadKind = ODataPayloadKind.Resource; } else if (edmType.TypeKind == EdmTypeKind.Collection && (edmType as IEdmCollectionType).ElementType.IsStructured()) { payloadKind = ODataPayloadKind.ResourceSet; } } if (payloadKind == ODataPayloadKind.Resource || payloadKind == ODataPayloadKind.ResourceSet) { // In V1/V2, we allowed System.Object type to be allowed to pass to ExecuteQuery. // Hence we need to explicitly check for System.Object to allow this if (edmType != null && !edmType.TypeKind.IsStructured()) { throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidNonEntityType(materializerType.FullName)); } ODataReaderWrapper reader = ODataReaderWrapper.Create(messageReader, payloadKind, edmType, responseInfo.ResponsePipeline); EntityTrackingAdapter entityTrackingAdapter = new EntityTrackingAdapter(responseInfo.EntityTracker, responseInfo.MergeOption, responseInfo.Model, responseInfo.Context); LoadPropertyResponseInfo loadPropertyResponseInfo = responseInfo as LoadPropertyResponseInfo; if (loadPropertyResponseInfo != null) { result = new ODataLoadNavigationPropertyMaterializer( messageReader, reader, materializerContext, entityTrackingAdapter, queryComponents, materializerType, plan, loadPropertyResponseInfo); } else { result = new ODataReaderEntityMaterializer( messageReader, reader, materializerContext, entityTrackingAdapter, queryComponents, materializerType, plan); } } else { switch (payloadKind) { case ODataPayloadKind.Value: result = new ODataValueMaterializer(messageReader, materializerContext, materializerType, queryComponents.SingleResult); break; case ODataPayloadKind.Collection: result = new ODataCollectionMaterializer(messageReader, materializerContext, materializerType, queryComponents.SingleResult); break; case ODataPayloadKind.Property: case ODataPayloadKind.IndividualProperty: // Top level properties cannot be of entity type. if (edmType != null && (edmType.TypeKind == EdmTypeKind.Entity || edmType.TypeKind == EdmTypeKind.Complex)) { throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidEntityType(materializerType.FullName)); } result = new ODataPropertyMaterializer(messageReader, materializerContext, materializerType, queryComponents.SingleResult); break; case ODataPayloadKind.EntityReferenceLinks: case ODataPayloadKind.EntityReferenceLink: result = new ODataLinksMaterializer(messageReader, materializerContext, materializerType, queryComponents.SingleResult); break; case ODataPayloadKind.Error: var odataError = messageReader.ReadError(); throw new ODataErrorException(odataError.Message, odataError); default: throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidResponsePayload(XmlConstants.DataWebNamespace)); } } return(result); } catch (Exception ex) { if (CommonUtil.IsCatchableExceptionType(ex)) { // Dispose the message reader in all error scenarios. messageReader.Dispose(); } throw; } }
private MaterializeAtom CreateMaterializer <T>(string content, string contentType, ProjectionPlan plan) { ResponseInfo info = new ResponseInfo(new RequestInfo(this.context), MergeOption.AppendOnly); QueryComponents qc = new QueryComponents(this.serviceUri, Util.ODataVersion4, typeof(T), null, null); Dictionary <string, string> headers = new Dictionary <string, string>(); headers.Add(XmlConstants.HttpContentType, contentType); var bytes = System.Text.Encoding.UTF8.GetBytes(content); TestResponseMessage responseMessage = new TestResponseMessage(headers, HttpStatusCode.OK, () => new System.IO.MemoryStream(bytes)); return(new MaterializeAtom(info, qc, plan, responseMessage, ODataPayloadKind.Unsupported)); }
private void TestMaterialization <T>(string content, string contentType, Action <MaterializeAtom> testAction, ProjectionPlan plan = null) { content = content.Replace("##BASEURI##", ServiceUri); using (MaterializeAtom materializer = CreateMaterializer <T>(content, contentType, plan)) { testAction(materializer); } }
internal static object ProjectionValueForPath(ODataEntityMaterializer materializer, MaterializerEntry entry, Type expectedType, ProjectionPath path) { if ((path.Count == 0) || ((path.Count == 1) && (path[0].Member == null))) { if (!entry.EntityHasBeenResolved) { materializer.Materialize(entry, expectedType, false); } return(entry.ResolvedObject); } object streamLink = null; ODataNavigationLink link = null; ODataProperty atomProperty = null; ICollection <ODataNavigationLink> navigationLinks = entry.NavigationLinks; IEnumerable <ODataProperty> properties = entry.Entry.Properties; ClientEdmModel model = ClientEdmModel.GetModel(materializer.ResponseInfo.MaxProtocolVersion); for (int i = 0; i < path.Count; i++) { Func <StreamDescriptor, bool> predicate = null; Func <ODataNavigationLink, bool> func2 = null; Func <ODataProperty, bool> func3 = null; Func <ODataProperty, bool> func4 = null; Func <ODataNavigationLink, bool> func5 = null; string propertyName; ProjectionPathSegment segment = path[i]; if (segment.Member != null) { bool flag = i == (path.Count - 1); propertyName = segment.Member; expectedType = segment.SourceTypeAs ?? expectedType; ClientPropertyAnnotation property = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(expectedType)).GetProperty(propertyName, false); if (property.IsStreamLinkProperty) { if (predicate == null) { predicate = sd => sd.Name == propertyName; } StreamDescriptor descriptor = entry.EntityDescriptor.StreamDescriptors.Where <StreamDescriptor>(predicate).SingleOrDefault <StreamDescriptor>(); if (descriptor == null) { if (segment.SourceTypeAs == null) { throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomMaterializer_PropertyMissing(propertyName, entry.Entry.Id)); } return(WebUtil.GetDefaultValue <DataServiceStreamLink>()); } streamLink = descriptor.StreamLink; } else { if (segment.SourceTypeAs != null) { if (func2 == null) { func2 = p => p.Name == propertyName; } if (!navigationLinks.Any <ODataNavigationLink>(func2)) { if (func3 == null) { func3 = p => p.Name == propertyName; } if (!properties.Any <ODataProperty>(func3) && flag) { return(WebUtil.GetDefaultValue(property.PropertyType)); } } } if (func4 == null) { func4 = p => p.Name == propertyName; } atomProperty = properties.Where <ODataProperty>(func4).FirstOrDefault <ODataProperty>(); if (func5 == null) { func5 = p => p.Name == propertyName; } link = ((atomProperty == null) && (navigationLinks != null)) ? navigationLinks.Where <ODataNavigationLink>(func5).FirstOrDefault <ODataNavigationLink>() : null; if ((link == null) && (atomProperty == null)) { throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomMaterializer_PropertyMissing(propertyName, entry.Entry.Id)); } if (link != null) { ValidatePropertyMatch(property, link); MaterializerNavigationLink link2 = MaterializerNavigationLink.GetLink(link); if (link2.Feed != null) { MaterializerFeed feed = MaterializerFeed.GetFeed(link2.Feed); Type implementationType = ClientTypeUtil.GetImplementationType(segment.ProjectionType, typeof(ICollection <>)); if (implementationType == null) { implementationType = ClientTypeUtil.GetImplementationType(segment.ProjectionType, typeof(IEnumerable <>)); } Type nestedExpectedType = implementationType.GetGenericArguments()[0]; Type projectionType = segment.ProjectionType; if (projectionType.IsInterfaceEx() || ODataMaterializer.IsDataServiceCollection(projectionType)) { projectionType = typeof(Collection <>).MakeGenericType(new Type[] { nestedExpectedType }); } IEnumerable list = (IEnumerable)Util.ActivatorCreateInstance(projectionType, new object[0]); MaterializeToList(materializer, list, nestedExpectedType, feed.Entries); if (ODataMaterializer.IsDataServiceCollection(segment.ProjectionType)) { list = (IEnumerable)Util.ActivatorCreateInstance(WebUtil.GetDataServiceCollectionOfT(new Type[] { nestedExpectedType }), new object[] { list, TrackingMode.None }); } ProjectionPlan plan = CreatePlanForShallowMaterialization(nestedExpectedType); materializer.FoundNextLinkForCollection(list, feed.Feed.NextPageLink, plan); streamLink = list; } else if (link2.Entry != null) { MaterializerEntry entry2 = link2.Entry; if (flag) { if ((entry2.Entry != null) && !entry2.EntityHasBeenResolved) { materializer.Materialize(entry2, property.PropertyType, false); } } else { CheckEntryToAccessNotNull(entry2, propertyName); } properties = entry2.Properties; navigationLinks = entry2.NavigationLinks; streamLink = entry2.ResolvedObject; entry = entry2; } } else { if (atomProperty.Value is ODataStreamReferenceValue) { streamLink = null; navigationLinks = ODataMaterializer.EmptyLinks; properties = ODataMaterializer.EmptyProperties; continue; } ValidatePropertyMatch(property, atomProperty); if (ClientTypeUtil.TypeOrElementTypeIsEntity(property.PropertyType)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.AtomMaterializer_InvalidEntityType(property.EntityCollectionItemType ?? property.PropertyType)); } if (property.IsPrimitiveOrComplexCollection) { object instance = streamLink ?? (entry.ResolvedObject ?? Util.ActivatorCreateInstance(expectedType, new object[0])); ODataMaterializer.ApplyDataValue(model.GetClientTypeAnnotation(model.GetOrCreateEdmType(instance.GetType())), atomProperty, materializer.ResponseInfo.IgnoreMissingProperties, materializer.ResponseInfo, instance); navigationLinks = ODataMaterializer.EmptyLinks; properties = ODataMaterializer.EmptyProperties; } else if (atomProperty.Value is ODataComplexValue) { ODataComplexValue complexValue = atomProperty.Value as ODataComplexValue; ODataMaterializer.MaterializeComplexTypeProperty(property.PropertyType, complexValue, materializer.ResponseInfo.IgnoreMissingProperties, materializer.ResponseInfo); properties = complexValue.Properties; navigationLinks = ODataMaterializer.EmptyLinks; } else { if ((atomProperty.Value == null) && !ClientTypeUtil.CanAssignNull(property.NullablePropertyType)) { throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomMaterializer_CannotAssignNull(atomProperty.Name, property.NullablePropertyType)); } ODataMaterializer.MaterializePrimitiveDataValue(property.NullablePropertyType, atomProperty); navigationLinks = ODataMaterializer.EmptyLinks; properties = ODataMaterializer.EmptyProperties; } streamLink = atomProperty.GetMaterializedValue(); } } expectedType = property.PropertyType; } } return(streamLink); }
public ODataEntityMaterializer(ResponseInfo responseInfo, QueryComponents queryComponents, Type expectedType, ProjectionPlan materializeEntryPlan) : base(responseInfo, expectedType) { this.materializeEntryPlan = materializeEntryPlan ?? CreatePlan(queryComponents); this.mergeOption = base.ResponseInfo.MergeOption; this.log = new AtomMaterializerLog(base.ResponseInfo); }
private void ApplyItemsToCollection(MaterializerEntry entry, ClientPropertyAnnotation property, IEnumerable items, Uri nextLink, ProjectionPlan continuationPlan) { Func <LinkDescriptor, bool> predicate = null; object instance = entry.ShouldUpdateFromPayload ? GetOrCreateCollectionProperty(entry.ResolvedObject, property, null) : null; ClientEdmModel model = ClientEdmModel.GetModel(base.ResponseInfo.MaxProtocolVersion); ClientTypeAnnotation clientTypeAnnotation = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(property.EntityCollectionItemType)); foreach (object obj3 in items) { if (!clientTypeAnnotation.ElementType.IsAssignableFrom(obj3.GetType())) { throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomMaterializer_EntryIntoCollectionMismatch(obj3.GetType().FullName, clientTypeAnnotation.ElementType.FullName)); } if (entry.ShouldUpdateFromPayload) { property.SetValue(instance, obj3, property.PropertyName, true); this.log.AddedLink(entry, property.PropertyName, obj3); } } if (entry.ShouldUpdateFromPayload) { this.FoundNextLinkForCollection(instance as IEnumerable, nextLink, continuationPlan); } else { this.FoundNextLinkForUnmodifiedCollection(property.GetValue(entry.ResolvedObject) as IEnumerable); } if ((this.mergeOption == MergeOption.OverwriteChanges) || (this.mergeOption == MergeOption.PreserveChanges)) { if (predicate == null) { predicate = delegate(LinkDescriptor x) { if (MergeOption.OverwriteChanges != this.mergeOption) { return(EntityStates.Added != x.State); } return(true); }; } foreach (object obj4 in (from x in base.ResponseInfo.EntityTracker.GetLinks(entry.ResolvedObject, property.PropertyName).Where <LinkDescriptor>(predicate) select x.Target).Except <object>(EnumerateAsElementType <object>(items))) { if (instance != null) { property.RemoveValue(instance, obj4); } this.log.RemovedLink(entry, property.PropertyName, obj4); } } }