private Expression[] ProcessActionInvokePostBody(IODataRequestMessage message, IEdmOperation operation) { using (var messageReader = new ODataMessageReader(message, this.GetReaderSettings())) { List <Expression> parameterValues = new List <Expression>(); var parameterReader = messageReader.CreateODataParameterReader(operation); while (parameterReader.Read()) { switch (parameterReader.State) { case ODataParameterReaderState.Value: { object clrValue = ODataObjectModelConverter.ConvertPropertyValue(parameterReader.Value); parameterValues.Add(Expression.Constant(clrValue)); break; } case ODataParameterReaderState.Collection: { ODataCollectionReader collectionReader = parameterReader.CreateCollectionReader(); object clrValue = ODataObjectModelConverter.ConvertPropertyValue(ODataObjectModelConverter.ReadCollectionParameterValue(collectionReader)); parameterValues.Add(Expression.Constant(clrValue, clrValue.GetType())); break; } case ODataParameterReaderState.Resource: { var entryReader = parameterReader.CreateResourceReader(); object clrValue = ODataObjectModelConverter.ReadEntityOrEntityCollection(entryReader, false); parameterValues.Add(Expression.Constant(clrValue, clrValue.GetType())); break; } case ODataParameterReaderState.ResourceSet: { var feedReader = parameterReader.CreateResourceSetReader(); var collectionList = ODataObjectModelConverter.ReadEntityOrEntityCollection(feedReader, true); parameterValues.Add(Expression.Constant(collectionList, collectionList.GetType())); break; } } } return(parameterValues.ToArray()); } }
/// <summary> /// Handle single entry, which from first level and $expand /// </summary> /// <param name="entry">Entry</param> /// <param name="entitySet">EntitySet</param> /// <param name="targetVersion">Target Version</param> /// <param name="selectExpandClause">Select and Expand Caluse</param> /// <param name="parentId">ParentId, string.Empty for first level</param> /// <param name="relationShip">Navigation property name, string.Empty for first level</param> private void GenerateDeltaItemFromEntry(object entry, IEdmNavigationSource entitySet, ODataVersion targetVersion, SelectExpandClause selectExpandClause, string parentId, string relationShip) { var deltaEntry = ODataObjectModelConverter.ConvertToODataEntry(entry, entitySet, targetVersion).Resource; // Verify entry if need to be written DateTime lastestUpdated = ((ClrObject)entry).UpdatedTime; if (lastestUpdated > DeltaSnapshot.TimeStamp) { var lastSegmentOfDeltaEntry = new ODataUriParser(this.DataSource.Model, ServiceConstants.ServiceBaseUri, deltaEntry.Id).ParsePath().LastSegment as KeySegment; deltaEntry.SetSerializationInfo(new ODataResourceSerializationInfo { NavigationSourceEntityTypeName = lastSegmentOfDeltaEntry.EdmType.ToString(), NavigationSourceKind = lastSegmentOfDeltaEntry.NavigationSource.NavigationSourceKind(), NavigationSourceName = lastSegmentOfDeltaEntry.NavigationSource.Name, }); this.DeltaItems.Add(deltaEntry); } // Verify if need added link bool ifDeleted = DeltaSnapshot.Entries.Remove(DeltaSnapshot.Entries.FirstOrDefault(p => p.Id == deltaEntry.Id.AbsoluteUri && p.ParentId == parentId && p.RelationShip == relationShip)); if ((!string.IsNullOrEmpty(parentId)) && ifDeleted == false) { var deltaLink = new ODataDeltaLink(new Uri(parentId), deltaEntry.Id, relationShip); var lastSegmentOfDeltaEntry = new ODataUriParser(this.DataSource.Model, ServiceConstants.ServiceBaseUri, deltaEntry.Id).ParsePath().LastSegment as KeySegment; deltaLink.SetSerializationInfo(new ODataDeltaSerializationInfo { NavigationSourceName = lastSegmentOfDeltaEntry.NavigationSource.Name, }); this.DeltaItems.Add(deltaLink); } // Handle $expand var expandedNavigationItems = selectExpandClause == null ? null : selectExpandClause.SelectedItems.OfType <ExpandedNavigationSelectItem>(); GenerateDeltaItemsFromExpand(entry, entitySet, targetVersion, expandedNavigationItems, deltaEntry.Id.AbsoluteUri); }
public override void Process(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage) { object result; if (this.HttpMethod == HttpMethod.GET) { // we cannot invoke same action request multiple times, so only Functions are allowed to do the server-driven paging this.QueryContext.InitializeServerDrivenPaging(this.PreferenceContext); result = this.ProcessFunction(); if (this.PreferenceContext.MaxPageSize.HasValue) { responseMessage.AddPreferenceApplied(string.Format("{0}={1}", ServiceConstants.Preference_MaxPageSize, this.QueryContext.appliedPageSize.Value)); } } else { // TODO: currently ETag feature does not support action operation result = this.ProcessAction(requestMessage); } if (result == null) { // Protocol 9.1.4 Response Code 204 No Content // A request returns 204 No Content if the requested resource has the null value, // or if the service applies a return=minimal preference. In this case, the response body MUST be empty. ResponseWriter.WriteEmptyResponse(responseMessage); return; } using (var messageWriter = this.CreateMessageWriter(responseMessage)) { if (this.QueryContext.Target.TypeKind == EdmTypeKind.None || this.QueryContext.Target.TypeKind == EdmTypeKind.EntityReference || this.QueryContext.Target.ElementTypeKind == EdmTypeKind.EntityReference) { throw Utility.BuildException(HttpStatusCode.NotImplemented, "Unsupported return type in operation.", null); } else if (this.QueryContext.Target.TypeKind == EdmTypeKind.Entity || this.QueryContext.Target.ElementTypeKind == EdmTypeKind.Entity || this.QueryContext.Target.TypeKind == EdmTypeKind.Complex || this.QueryContext.Target.ElementTypeKind == EdmTypeKind.Complex) { ODataWriter resultWriter; IEdmNavigationSource entitySource = this.QueryContext.OperationResultSource ?? this.QueryContext.Target.NavigationSource; if (this.QueryContext.Target.TypeKind == EdmTypeKind.Collection) { IEdmEntitySetBase entitySet = (IEdmEntitySetBase)entitySource; resultWriter = messageWriter.CreateODataResourceSetWriter(entitySet, (IEdmStructuredType)this.QueryContext.Target.ElementType); ResponseWriter.WriteFeed(resultWriter, (IEdmStructuredType)this.QueryContext.Target.ElementType, result as IEnumerable, entitySet, ODataVersion.V4, this.QueryContext.QuerySelectExpandClause, this.QueryContext.TotalCount, null, this.QueryContext.NextLink, this.RequestHeaders); } else { if (this.HttpMethod == HttpMethod.GET) { var currentETag = Utility.GetETagValue(result); // if the current entity has ETag field if (currentETag != null) { string requestETag; if (Utility.TryGetIfNoneMatch(this.RequestHeaders, out requestETag) && (requestETag == ServiceConstants.ETagValueAsterisk || requestETag == currentETag)) { ResponseWriter.WriteEmptyResponse(responseMessage, HttpStatusCode.NotModified); return; } responseMessage.SetHeader(ServiceConstants.HttpHeaders.ETag, currentETag); } } resultWriter = messageWriter.CreateODataResourceWriter(entitySource, (IEdmStructuredType)this.QueryContext.Target.Type); ResponseWriter.WriteEntry(resultWriter, result, entitySource, ODataVersion.V4, this.QueryContext.QuerySelectExpandClause, this.RequestHeaders); } } else { ODataProperty property = new ODataProperty() { Name = "value", Value = ODataObjectModelConverter.CreateODataValue(result) }; messageWriter.WriteProperty(property); } } }
public override void Process(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage) { if (this.TryDispatch(requestMessage, responseMessage)) { return; } this.QueryContext.InitializeServerDrivenPaging(this.PreferenceContext); this.QueryContext.InitializeTrackingChanges(this.PreferenceContext); object queryResults = this.QueryContext.ResolveQuery(this.DataSource); if (queryResults == null) { // For individual property or $value if (this.QueryContext.Target.Property != null) { // Protocol 9.1.4 Response Code 204 No Content // A request returns 204 No Content if the requested resource has the null value, // or if the service applies a return=minimal preference. In this case, the response body MUST be empty. ResponseWriter.WriteEmptyResponse(responseMessage); return; } else { throw Utility.BuildException(HttpStatusCode.NotFound); } } // Handle the prefer of "odata.include-annotations", including it in response header if (!string.IsNullOrEmpty(this.PreferenceContext.IncludeAnnotations)) { responseMessage.AddPreferenceApplied(string.Format("{0}={1}", ServiceConstants.Preference_IncludeAnnotations, this.PreferenceContext.IncludeAnnotations)); } if (this.PreferenceContext.MaxPageSize.HasValue) { responseMessage.AddPreferenceApplied(string.Format("{0}={1}", ServiceConstants.Preference_MaxPageSize, this.QueryContext.appliedPageSize.Value)); } if (this.PreferenceContext.TrackingChanges) { responseMessage.AddPreferenceApplied(ServiceConstants.Preference_TrackChanging); } responseMessage.SetStatusCode(HttpStatusCode.OK); using (var messageWriter = this.CreateMessageWriter(responseMessage)) { IEdmNavigationSource navigationSource = this.QueryContext.Target.NavigationSource; IEnumerable iEnumerableResults = queryResults as IEnumerable; if (this.QueryContext.Target.IsReference && this.QueryContext.Target.TypeKind == EdmTypeKind.Collection) { // Query a $ref collection IList <ODataEntityReferenceLink> links = new List <ODataEntityReferenceLink>(); foreach (var iEnumerableResult in iEnumerableResults) { var link = new ODataEntityReferenceLink { Url = Utility.BuildLocationUri(this.QueryContext, iEnumerableResult), }; links.Add(link); } ODataEntityReferenceLinks linksCollection = new ODataEntityReferenceLinks() { Links = links, NextPageLink = this.QueryContext.NextLink }; linksCollection.InstanceAnnotations.Add(new ODataInstanceAnnotation("Links.Annotation", new ODataPrimitiveValue(true))); messageWriter.WriteEntityReferenceLinks(linksCollection); } else if (this.QueryContext.Target.IsReference && this.QueryContext.Target.TypeKind == EdmTypeKind.Entity) { // Query a $ref var link = new ODataEntityReferenceLink { Url = Utility.BuildLocationUri(this.QueryContext, queryResults), }; link.InstanceAnnotations.Add(new ODataInstanceAnnotation("Link.Annotation", new ODataPrimitiveValue(true))); messageWriter.WriteEntityReferenceLink(link); } else if (this.QueryContext.Target.NavigationSource != null && this.QueryContext.Target.TypeKind == EdmTypeKind.Collection) { // Query a feed IEdmEntitySetBase entitySet = navigationSource as IEdmEntitySetBase; IEdmEntityType entityType = this.QueryContext.Target.ElementType as IEdmEntityType; if (entitySet == null || entityType == null) { throw new InvalidOperationException("Invalid target when query feed."); } ODataWriter resultWriter = messageWriter.CreateODataFeedWriter(entitySet, entityType); ResponseWriter.WriteFeed(resultWriter, iEnumerableResults, entitySet, ODataVersion.V4, this.QueryContext.QuerySelectExpandClause, this.QueryContext.TotalCount, this.QueryContext.DeltaLink, this.QueryContext.NextLink, this.RequestHeaders); resultWriter.Flush(); } else if (this.QueryContext.Target.NavigationSource != null && this.QueryContext.Target.TypeKind == EdmTypeKind.Entity) { var currentETag = Utility.GetETagValue(queryResults); // if the current entity has ETag field if (currentETag != null) { string requestETag; if (Utility.TryGetIfNoneMatch(this.RequestHeaders, out requestETag) && (requestETag == ServiceConstants.ETagValueAsterisk || requestETag == currentETag)) { ResponseWriter.WriteEmptyResponse(responseMessage, HttpStatusCode.NotModified); return; } responseMessage.SetHeader(ServiceConstants.HttpHeaders.ETag, currentETag); } // Query a single entity IEdmEntityType entityType = this.QueryContext.Target.Type as IEdmEntityType; ODataWriter resultWriter = messageWriter.CreateODataEntryWriter(navigationSource, entityType); ResponseWriter.WriteEntry(resultWriter, queryResults, navigationSource, ODataVersion.V4, this.QueryContext.QuerySelectExpandClause, this.RequestHeaders); resultWriter.Flush(); } else if (this.QueryContext.Target.Property != null && !this.QueryContext.Target.IsRawValue) { // Query a individual property ODataProperty property = ODataObjectModelConverter.CreateODataProperty(queryResults, this.QueryContext.Target.Property.Name); messageWriter.WriteProperty(property); } else if (this.QueryContext.Target.IsRawValue) { // Query a $value or $count var propertyValue = ODataObjectModelConverter.CreateODataValue(queryResults); messageWriter.WriteValue(propertyValue); } else { throw Utility.BuildException(HttpStatusCode.NotImplemented); } } }
private Expression[] ProcessActionInvokePostBody(IODataRequestMessage message, IEdmOperation operation) { using (var messageReader = new ODataMessageReader(message, this.GetReaderSettings(), this.DataSource.Model)) { List <Expression> parameterValues = new List <Expression>(); var parameterReader = messageReader.CreateODataParameterReader(operation); while (parameterReader.Read()) { switch (parameterReader.State) { case ODataParameterReaderState.Value: { object clrValue = ODataObjectModelConverter.ConvertPropertyValue(parameterReader.Value); parameterValues.Add(Expression.Constant(clrValue)); break; } case ODataParameterReaderState.Collection: { ODataCollectionReader collectionReader = parameterReader.CreateCollectionReader(); object clrValue = ODataObjectModelConverter.ConvertPropertyValue(ODataObjectModelConverter.ReadCollectionParameterValue(collectionReader)); parameterValues.Add(Expression.Constant(clrValue, clrValue.GetType())); break; } case ODataParameterReaderState.Entry: { var entryReader = parameterReader.CreateEntryReader(); object clrValue = ODataObjectModelConverter.ConvertPropertyValue(ODataObjectModelConverter.ReadEntryParameterValue(entryReader)); parameterValues.Add(Expression.Constant(clrValue, clrValue.GetType())); break; } case ODataParameterReaderState.Feed: { IList collectionList = null; var feedReader = parameterReader.CreateFeedReader(); while (feedReader.Read()) { if (feedReader.State == ODataReaderState.EntryEnd) { object clrItem = ODataObjectModelConverter.ConvertPropertyValue(feedReader.Item); if (collectionList == null) { Type itemType = clrItem.GetType(); Type listType = typeof(List <>).MakeGenericType(new[] { itemType }); collectionList = (IList)Utility.QuickCreateInstance(listType); } collectionList.Add(clrItem); } } parameterValues.Add(Expression.Constant(collectionList, collectionList.GetType())); break; } } } return(parameterValues.ToArray()); } }
private static void UpdateCore(object target, string propertyName, object propertyValue) { var odataComplexValue = propertyValue as ODataComplexValue; var odataCollectionValue = propertyValue as ODataCollectionValue; var odataEnumValue = propertyValue as ODataEnumValue; var odataPrimitiveValue = propertyValue as ODataPrimitiveValue; if (odataComplexValue != null) { var property = target.GetType().GetProperty(propertyName); if (property != null) { var value = property.GetValue(target, null); if (value == null) { var valueType = EdmClrTypeUtils.GetInstanceType(odataComplexValue.TypeName); var propertyType = property.PropertyType; if (valueType.IsSubclassOf(propertyType) || valueType == propertyType) { value = Utility.QuickCreateInstance(valueType); } else { throw new InvalidOperationException(string.Format("{0} is not equal or derived from {1}", valueType, propertyType)); } property.SetValue(target, value, null); } foreach (var p in odataComplexValue.Properties) { UpdateCore(value, p.Name, p.Value); } return; } } else if (odataCollectionValue != null) { var property = target.GetType().GetProperty(propertyName); if (property != null) { var collection = Utility.QuickCreateInstance(property.PropertyType); foreach (var item in odataCollectionValue.Items) { var itemType = property.PropertyType.GetGenericArguments().Single(); odataComplexValue = item as ODataComplexValue; odataCollectionValue = item as ODataCollectionValue; object collectionItem = null; if (odataComplexValue != null) { // TODO: call Create method to new instance instead collectionItem = Utility.QuickCreateInstance(itemType); foreach (var p in odataComplexValue.Properties) { UpdateCore(collectionItem, p.Name, p.Value); } } else if (odataCollectionValue != null) { // TODO, check should support this type or not throw new NotImplementedException(); } else { collectionItem = ODataObjectModelConverter.ConvertPropertyValue(item, itemType); } property.PropertyType.GetMethod("Add").Invoke(collection, new object[] { collectionItem }); } property.SetValue(target, collection, null); return; } } else { var property = target.GetType().GetProperty(propertyName); if (property != null) { property.SetValue(target, ODataObjectModelConverter.ConvertPropertyValue(propertyValue, property.PropertyType), null); return; } } var openClrObject = target as OpenClrObject; if (openClrObject != null) { var structuredType = (IEdmStructuredType)EdmClrTypeUtils.GetEdmType(DataSourceManager.GetCurrentDataSource().Model, openClrObject); //check if the edmType is an open type if (structuredType.IsOpen) { if (odataCollectionValue != null) { // Collection of Edm.String if (odataCollectionValue.TypeName == "Collection(Edm.String)") { var collection = new Collection <string>(); foreach (var it in odataCollectionValue.Items) { collection.Add(it as string); } openClrObject.OpenProperties[propertyName] = collection; } else { // TODO: handle other types. throw new NotImplementedException(); } } else if (odataComplexValue != null) { var type = EdmClrTypeUtils.GetInstanceType(odataComplexValue.TypeName); var value = Utility.QuickCreateInstance(type); foreach (var property in odataComplexValue.Properties) { UpdateCore(value, property.Name, property.Value); } openClrObject.OpenProperties[propertyName] = value; } else if (odataEnumValue != null) { var type = EdmClrTypeUtils.GetInstanceType(odataEnumValue.TypeName); openClrObject.OpenProperties[propertyName] = ODataObjectModelConverter.ConvertPropertyValue(propertyValue, type); } else if (odataPrimitiveValue != null) { openClrObject.OpenProperties[propertyName] = odataPrimitiveValue.Value; } else { openClrObject.OpenProperties[propertyName] = propertyValue; } } } }