/// <summary> /// Converts the object to ODataResource or ODataEntityReferenceLink. /// </summary> /// <param name="value">The value of the <see cref="UriOperationParameter"/>.</param> /// <param name="elementType">The type of the value</param> /// <param name="useEntityReference">If true, use entity reference, instead of entity to serialize the parameter.</param> /// <returns>The converted result.</returns> private object ConvertToEntityValue(object value, Type elementType, bool useEntityReference) { object valueInODataFormat; if (!useEntityReference) { valueInODataFormat = this.propertyConverter.CreateODataEntry(elementType, value); ODataResource entry = (ODataResource)valueInODataFormat; if (entry.TypeAnnotation == null || string.IsNullOrEmpty(entry.TypeAnnotation.TypeName)) { throw Error.InvalidOperation(Strings.DataServiceException_GeneralError); } } else { EntityDescriptor resource = this.requestInfo.EntityTracker.GetEntityDescriptor(value); Uri link = resource.GetLatestIdentity(); valueInODataFormat = new ODataEntityReferenceLink() { Url = link, }; } return(valueInODataFormat); }
/// <summary> /// Creates an ODataEntry for the given EntityDescriptor and fills in its ODataLib metadata. /// </summary> /// <param name="entityDescriptor">The entity descriptor.</param> /// <param name="serverTypeName">Name of the server type.</param> /// <param name="entityType">The client-side entity type.</param> /// <param name="clientFormat">The current client format.</param> /// <returns>An odata entry with its metadata filled in.</returns> internal static ODataEntry CreateODataEntry(EntityDescriptor entityDescriptor, string serverTypeName, ClientTypeAnnotation entityType, DataServiceClientFormat clientFormat) { ODataEntry entry = new ODataEntry(); // If the client type name is different from the server type name, then add SerializationTypeNameAnnotation // which tells ODataLib to write the type name in the annotation in the payload. if (entityType.ElementTypeName != serverTypeName) { entry.SetAnnotation(new SerializationTypeNameAnnotation { TypeName = serverTypeName }); } // We always need to write the client type name, since this is the type name used by ODataLib // to resolve the entity type using EdmModel.FindSchemaElement. entry.TypeName = entityType.ElementTypeName; // Continue to send the entry's ID in update payloads in Atom for compatibility with V1-V3, // but for JSON-Light we do not want the extra information on the wire. if (clientFormat.UsingAtom && EntityStates.Modified == entityDescriptor.State) { // <id>http://host/service/entityset(key)</id> entry.Id = entityDescriptor.GetLatestIdentity(); } if (entityDescriptor.IsMediaLinkEntry || entityType.IsMediaLinkEntry) { // Since we are already enabled EnableWcfDataServicesClientBehavior in the writer settings, // setting the MediaResource value will tell ODataLib to write MLE payload, irrespective of // what the metadata says. entry.MediaResource = new ODataStreamReferenceValue(); } return(entry); }
/// <summary> /// Writes an entity reference link. /// </summary> /// <param name="binding">The link descriptor.</param> /// <param name="requestMessage">The request message used for writing the payload.</param> internal void WriteEntityReferenceLink(LinkDescriptor binding, ODataRequestMessageWrapper requestMessage) #endif { using (ODataMessageWriter messageWriter = Serializer.CreateMessageWriter(requestMessage, this.requestInfo, false /*isParameterPayload*/)) { EntityDescriptor targetResource = this.requestInfo.EntityTracker.GetEntityDescriptor(binding.Target); Uri targetReferenceLink = targetResource.GetLatestIdentity(); if (targetReferenceLink == null) { #if DEBUG Debug.Assert(isBatch, "we should be cross-referencing entities only in batch scenarios"); #endif targetReferenceLink = UriUtil.CreateUri("$" + targetResource.ChangeOrder.ToString(CultureInfo.InvariantCulture), UriKind.Relative); } ODataEntityReferenceLink referenceLink = new ODataEntityReferenceLink(); referenceLink.Url = targetReferenceLink; messageWriter.WriteEntityReferenceLink(referenceLink); } }
/// <summary> /// Creates an ODataEntry for the given EntityDescriptor and fills in its ODataLib metadata. /// </summary> /// <param name="entityDescriptor">The entity descriptor.</param> /// <param name="serverTypeName">Name of the server type.</param> /// <param name="entityType">The client-side entity type.</param> /// <param name="clientFormat">The current client format.</param> /// <returns>An odata entry with its metadata filled in.</returns> internal static ODataEntry CreateODataEntry(EntityDescriptor entityDescriptor, string serverTypeName, ClientTypeAnnotation entityType, DataServiceClientFormat clientFormat) { ODataEntry entry = new ODataEntry(); // If the client type name is different from the server type name, then add SerializationTypeNameAnnotation // which tells ODataLib to write the type name in the annotation in the payload. if (entityType.ElementTypeName != serverTypeName) { entry.SetAnnotation(new SerializationTypeNameAnnotation { TypeName = serverTypeName }); } // We always need to write the client type name, since this is the type name used by ODataLib // to resolve the entity type using EdmModel.FindSchemaElement. entry.TypeName = entityType.ElementTypeName; // Continue to send the entry's ID in update payloads in Atom for compatibility with V1-V3, // but for JSON-Light we do not want the extra information on the wire. if (clientFormat.UsingAtom && EntityStates.Modified == entityDescriptor.State) { // <id>http://host/service/entityset(key)</id> entry.Id = entityDescriptor.GetLatestIdentity(); } if (entityDescriptor.IsMediaLinkEntry || entityType.IsMediaLinkEntry) { // Since we are already enabled EnableWcfDataServicesClientBehavior in the writer settings, // setting the MediaResource value will tell ODataLib to write MLE payload, irrespective of // what the metadata says. entry.MediaResource = new ODataStreamReferenceValue(); } return entry; }
/// <summary> /// Materialize the response payload. /// </summary> /// <param name="entityDescriptor">entity descriptor whose response is getting materialized.</param> /// <param name="responseInfo">information about the response to be materialized.</param> /// <param name="etag">etag value, if specified in the response header.</param> private void MaterializeResponse(EntityDescriptor entityDescriptor, ResponseInfo responseInfo, string etag) { using (MaterializeAtom materializer = this.GetMaterializer(entityDescriptor, responseInfo)) { materializer.SetInsertingObject(entityDescriptor.Entity); object materializedEntity = null; foreach (object x in materializer) { Debug.Assert(materializedEntity == null, "entity == null"); if (materializedEntity != null) { Error.ThrowInternalError(InternalError.MaterializerReturningMoreThanOneEntity); } materializedEntity = x; } Debug.Assert(null != entityDescriptor.GetLatestIdentity(), "updated inserted should always gain an identity"); Debug.Assert(materializedEntity == entityDescriptor.Entity, "x == entityDescriptor.Entity, should have same object generated by response"); Debug.Assert(EntityStates.Unchanged == entityDescriptor.State, "should have moved out of insert"); Debug.Assert(this.RequestInfo.EntityTracker.TryGetEntityDescriptor(entityDescriptor.GetLatestIdentity()) != null, "should have identity tracked"); // If there was no etag specified in the payload, then we need to set the etag from the header if (entityDescriptor.GetLatestETag() == null) { entityDescriptor.ETag = etag; } } }
/// <summary> /// Validates that the link descriptor source and target have identities. /// </summary> /// <param name="binding">The binding.</param> /// <param name="sourceResource">The source resource.</param> /// <param name="targetResource">The target resource.</param> private static void ValidateLinkDescriptorSourceAndTargetHaveIdentities(LinkDescriptor binding, EntityDescriptor sourceResource, EntityDescriptor targetResource) { Debug.Assert(!binding.ContentGeneratedForSave, "already saved link"); // In non-batch scenarios, the source should always have an identity if (null == sourceResource.GetLatestIdentity()) { binding.ContentGeneratedForSave = true; Debug.Assert(EntityStates.Added == sourceResource.State, "expected added state"); throw Error.InvalidOperation(Strings.Context_LinkResourceInsertFailure, sourceResource.SaveError); } if (null != targetResource && null == targetResource.GetLatestIdentity()) { binding.ContentGeneratedForSave = true; Debug.Assert(EntityStates.Added == targetResource.State, "expected added state"); throw Error.InvalidOperation(Strings.Context_LinkResourceInsertFailure, targetResource.SaveError); } }