Skip to content

Commit 1f08dc0

Browse files
Feature/update bulk ops serialization (#2697)
bulk ops serialization
1 parent cda7e83 commit 1f08dc0

22 files changed

Lines changed: 2237 additions & 1053 deletions

src/Microsoft.AspNet.OData.Shared/DeltaSetOfT.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace Microsoft.AspNet.OData
1717
/// </summary>
1818
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
1919
[NonValidatingParameterBinding]
20-
internal class DeltaSet<TStructuralType> : Collection<IDeltaSetItem>, IDeltaSet where TStructuralType : class
20+
public class DeltaSet<TStructuralType> : Collection<IDeltaSetItem>, IDeltaSet where TStructuralType : class
2121
{
2222
private Type _clrType;
2323
private IList<string> _keys;

src/Microsoft.AspNet.OData.Shared/Formatter/ODataOutputFormatterHelper.cs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ internal static bool CanWriteType(
9595
ODataPayloadKind? payloadKind;
9696

9797
Type elementType;
98-
if (typeof(IEdmObject).IsAssignableFrom(type) ||
98+
if (typeof(IEdmObject).IsAssignableFrom(type) ||
99+
typeof(IDeltaSet).IsAssignableFrom(type) ||
99100
(TypeHelper.IsCollection(type, out elementType) && typeof(IEdmObject).IsAssignableFrom(elementType)))
100101
{
101102
payloadKind = GetEdmObjectPayloadKind(type, internalRequest);
@@ -156,7 +157,16 @@ internal static void WriteToStream(
156157

157158
ODataMessageWriterSettings writerSettings = internalRequest.WriterSettings;
158159
writerSettings.BaseUri = baseAddress;
159-
writerSettings.Version = version;
160+
161+
if (serializer.ODataPayloadKind == ODataPayloadKind.Delta)
162+
{
163+
writerSettings.Version = ODataVersion.V401;
164+
}
165+
else
166+
{
167+
writerSettings.Version = version;
168+
}
169+
160170
writerSettings.Validations = writerSettings.Validations & ~ValidationKinds.ThrowOnUndeclaredPropertyForNonOpenType;
161171

162172
string metadataLink = internaUrlHelper.CreateODataLink(MetadataSegment.Instance);
@@ -207,6 +217,7 @@ internal static void WriteToStream(
207217
writeContext.Path = path;
208218
writeContext.MetadataLevel = metadataLevel;
209219
writeContext.QueryOptions = internalRequest.Context.QueryOptions;
220+
writeContext.Type = type;
210221

211222
//Set the SelectExpandClause on the context if it was explicitly specified.
212223
if (selectExpandDifferentFromQueryOptions != null)
@@ -251,7 +262,7 @@ internal static void WriteToStream(
251262
{
252263
return ODataPayloadKind.ResourceSet;
253264
}
254-
else if (typeof(IEdmChangedObject).IsAssignableFrom(elementType))
265+
else if (typeof(IDeltaSetItem).IsAssignableFrom(elementType) || typeof(IEdmChangedObject).IsAssignableFrom(elementType))
255266
{
256267
return ODataPayloadKind.Delta;
257268
}

src/Microsoft.AspNet.OData.Shared/Formatter/Serialization/DefaultODataSerializerProvider.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ internal ODataSerializer GetODataPayloadSerializerImpl(Type type, Func<IEdmModel
112112
{
113113
return _rootContainer.GetRequiredService<ODataMetadataSerializer>();
114114
}
115+
else if (TypeHelper.IsTypeAssignableFrom(typeof(IDeltaSet), type))
116+
{
117+
return _rootContainer.GetRequiredService<ODataDeltaFeedSerializer>();
118+
}
115119

116120
// Get the model. Using a Func<IEdmModel> to delay evaluation of the model
117121
// until after the above checks have passed.

src/Microsoft.AspNet.OData.Shared/Formatter/Serialization/ODataDeltaFeedSerializer.cs

Lines changed: 98 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@
66
//------------------------------------------------------------------------------
77

88
using System;
9+
using System.CodeDom;
910
using System.Collections;
11+
using System.Collections.Generic;
1012
using System.Diagnostics.Contracts;
13+
using System.Reflection;
1114
using System.Runtime.Serialization;
1215
using System.Threading.Tasks;
1316
using Microsoft.AspNet.OData.Builder;
@@ -25,6 +28,7 @@ namespace Microsoft.AspNet.OData.Formatter.Serialization
2528
public class ODataDeltaFeedSerializer : ODataEdmTypeSerializer
2629
{
2730
private const string DeltaFeed = "deltafeed";
31+
IEdmStructuredTypeReference _elementType;
2832

2933
/// <summary>
3034
/// Initializes a new instance of <see cref="ODataDeltaFeedSerializer"/>.
@@ -60,6 +64,7 @@ public override void WriteObject(object graph, Type type, ODataMessageWriter mes
6064
}
6165

6266
IEdmTypeReference feedType = writeContext.GetEdmType(graph, type);
67+
6368
Contract.Assert(feedType != null);
6469

6570
IEdmEntityTypeReference entityType = GetResourceType(feedType).AsEntity();
@@ -93,6 +98,7 @@ public override async Task WriteObjectAsync(object graph, Type type, ODataMessag
9398
}
9499

95100
IEdmTypeReference feedType = writeContext.GetEdmType(graph, type);
101+
96102
Contract.Assert(feedType != null);
97103

98104
IEdmEntityTypeReference entityType = GetResourceType(feedType).AsEntity();
@@ -186,6 +192,7 @@ private void WriteFeed(IEnumerable enumerable, IEdmTypeReference feedType, OData
186192
Contract.Assert(feedType != null);
187193

188194
IEdmStructuredTypeReference elementType = GetResourceType(feedType);
195+
_elementType = elementType;
189196

190197
if (elementType.IsComplex())
191198
{
@@ -234,13 +241,9 @@ private void WriteFeed(IEnumerable enumerable, IEdmTypeReference feedType, OData
234241
}
235242

236243
lastResource = entry;
237-
IEdmChangedObject edmChangedObject = entry as IEdmChangedObject;
238-
if (edmChangedObject == null)
239-
{
240-
throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, enumerable.GetType().FullName));
241-
}
244+
EdmDeltaEntityKind deltaEntityKind = GetDeltaEntityKind(enumerable, entry, writeContext);
242245

243-
switch (edmChangedObject.DeltaKind)
246+
switch (deltaEntityKind)
244247
{
245248
case EdmDeltaEntityKind.DeletedEntry:
246249
WriteDeltaDeletedEntry(entry, writer, writeContext);
@@ -254,6 +257,7 @@ private void WriteFeed(IEnumerable enumerable, IEdmTypeReference feedType, OData
254257
case EdmDeltaEntityKind.Entry:
255258
{
256259
ODataResourceSerializer entrySerializer = SerializerProvider.GetEdmTypeSerializer(elementType) as ODataResourceSerializer;
260+
257261
if (entrySerializer == null)
258262
{
259263
throw new SerializationException(
@@ -289,6 +293,7 @@ private async Task WriteFeedAsync(IEnumerable enumerable, IEdmTypeReference feed
289293
Contract.Assert(feedType != null);
290294

291295
IEdmStructuredTypeReference elementType = GetResourceType(feedType);
296+
_elementType = elementType;
292297

293298
if (elementType.IsComplex())
294299
{
@@ -337,13 +342,9 @@ private async Task WriteFeedAsync(IEnumerable enumerable, IEdmTypeReference feed
337342
}
338343

339344
lastResource = entry;
340-
IEdmChangedObject edmChangedObject = entry as IEdmChangedObject;
341-
if (edmChangedObject == null)
342-
{
343-
throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, enumerable.GetType().FullName));
344-
}
345+
EdmDeltaEntityKind deltaEntityKind = GetDeltaEntityKind(enumerable, entry, writeContext);
345346

346-
switch (edmChangedObject.DeltaKind)
347+
switch (deltaEntityKind)
347348
{
348349
case EdmDeltaEntityKind.DeletedEntry:
349350
await WriteDeltaDeletedEntryAsync(entry, writer, writeContext);
@@ -441,13 +442,25 @@ public virtual ODataDeltaResourceSet CreateODataDeltaFeed(IEnumerable feedInstan
441442
/// <param name="writeContext">The <see cref="ODataSerializerContext"/>.</param>
442443
public virtual void WriteDeltaDeletedEntry(object graph, ODataWriter writer, ODataSerializerContext writeContext)
443444
{
444-
ODataDeletedResource deletedResource = GetDeletedResource(graph);
445+
ODataResourceSerializer serializer = SerializerProvider.GetEdmTypeSerializer(_elementType) as ODataResourceSerializer;
446+
447+
if (serializer == null)
448+
{
449+
throw new SerializationException(
450+
Error.Format(SRResources.TypeCannotBeSerialized, _elementType.FullName()));
451+
}
452+
453+
ResourceContext resourceContext = serializer.GetResourceContext(graph, writeContext);
454+
SelectExpandNode selectExpandNode = serializer.CreateSelectExpandNode(resourceContext);
445455

446-
if (deletedResource != null)
456+
if (selectExpandNode != null)
447457
{
458+
ODataDeletedResource deletedResource = GetDeletedResource(graph, resourceContext, serializer, selectExpandNode, writeContext.IsUntyped);
448459
writer.WriteStart(deletedResource);
460+
serializer.WriteDeltaComplexProperties(selectExpandNode, resourceContext, writer);
449461
writer.WriteEnd();
450462
}
463+
451464
}
452465

453466
/// <summary>
@@ -459,10 +472,22 @@ public virtual void WriteDeltaDeletedEntry(object graph, ODataWriter writer, ODa
459472
/// <param name="writeContext">The <see cref="ODataSerializerContext"/>.</param>
460473
public virtual async Task WriteDeltaDeletedEntryAsync(object graph, ODataWriter writer, ODataSerializerContext writeContext)
461474
{
462-
ODataDeletedResource deletedResource = GetDeletedResource(graph);
463-
if (deletedResource != null)
475+
ODataResourceSerializer serializer = SerializerProvider.GetEdmTypeSerializer(_elementType) as ODataResourceSerializer;
476+
477+
if (serializer == null)
478+
{
479+
throw new SerializationException(
480+
Error.Format(SRResources.TypeCannotBeSerialized, _elementType.FullName()));
481+
}
482+
483+
ResourceContext resourceContext = serializer.GetResourceContext(graph, writeContext);
484+
SelectExpandNode selectExpandNode = serializer.CreateSelectExpandNode(resourceContext);
485+
486+
if (selectExpandNode != null)
464487
{
488+
ODataDeletedResource deletedResource = GetDeletedResource(graph, resourceContext, serializer, selectExpandNode, writeContext.IsUntyped);
465489
await writer.WriteStartAsync(deletedResource);
490+
await serializer.WriteDeltaComplexPropertiesAsync(selectExpandNode, resourceContext, writer);
466491
await writer.WriteEndAsync();
467492
}
468493
}
@@ -531,22 +556,41 @@ public async Task WriteDeltaLinkAsync(object graph, ODataWriter writer, ODataSer
531556
}
532557
}
533558

534-
private ODataDeletedResource GetDeletedResource(object graph)
559+
private ODataDeletedResource GetDeletedResource(object graph, ResourceContext resourceContext, ODataResourceSerializer serializer, SelectExpandNode selectExpandNode, bool isUntyped)
535560
{
536-
EdmDeltaDeletedEntityObject edmDeltaDeletedEntity = graph as EdmDeltaDeletedEntityObject;
537-
if (edmDeltaDeletedEntity == null)
561+
string navigationSource;
562+
ODataDeletedResource deletedResource = serializer.CreateDeletedResource(selectExpandNode, resourceContext);
563+
564+
if (isUntyped)
538565
{
539-
throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, graph.GetType().FullName));
566+
EdmDeltaDeletedEntityObject edmDeltaDeletedEntity = graph as EdmDeltaDeletedEntityObject;
567+
if (edmDeltaDeletedEntity == null)
568+
{
569+
throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, graph.GetType().FullName));
570+
}
571+
572+
deletedResource.Id = StringToUri(edmDeltaDeletedEntity.Id ?? string.Empty);
573+
deletedResource.Reason = edmDeltaDeletedEntity.Reason;
574+
navigationSource = edmDeltaDeletedEntity.NavigationSource?.Name;
540575
}
576+
else
577+
{
578+
IDeltaDeletedEntityObject deltaDeletedEntity = graph as IDeltaDeletedEntityObject;
579+
if (deltaDeletedEntity == null)
580+
{
581+
throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, graph.GetType().FullName));
582+
}
541583

542-
Uri id = StringToUri(edmDeltaDeletedEntity.Id);
543-
ODataDeletedResource deletedResource = new ODataDeletedResource(id, edmDeltaDeletedEntity.Reason);
584+
deletedResource.Id = deltaDeletedEntity.Id;
585+
deletedResource.Reason = deltaDeletedEntity.Reason;
586+
navigationSource = deltaDeletedEntity.NavigationSource;
587+
}
544588

545-
if (edmDeltaDeletedEntity.NavigationSource != null)
589+
if (navigationSource != null)
546590
{
547591
ODataResourceSerializationInfo serializationInfo = new ODataResourceSerializationInfo
548592
{
549-
NavigationSourceName = edmDeltaDeletedEntity.NavigationSource.Name
593+
NavigationSourceName = navigationSource
550594
};
551595
deletedResource.SetSerializationInfo(serializationInfo);
552596
}
@@ -621,5 +665,35 @@ internal static Uri StringToUri(string uriString)
621665

622666
return uri;
623667
}
668+
669+
private EdmDeltaEntityKind GetDeltaEntityKind(IEnumerable enumerable, object entry, ODataSerializerContext writeContext)
670+
{
671+
EdmDeltaEntityKind deltaEntityKind;
672+
673+
if (writeContext.IsUntyped)
674+
{
675+
IEdmChangedObject edmChangedObject = entry as IEdmChangedObject;
676+
677+
if (edmChangedObject == null)
678+
{
679+
throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, enumerable.GetType().FullName));
680+
}
681+
682+
deltaEntityKind = edmChangedObject.DeltaKind;
683+
}
684+
else
685+
{
686+
IDeltaSetItem deltaSetItem = entry as IDeltaSetItem;
687+
688+
if (deltaSetItem == null)
689+
{
690+
throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, enumerable.GetType().FullName));
691+
}
692+
693+
deltaEntityKind = deltaSetItem.DeltaKind;
694+
}
695+
696+
return deltaEntityKind;
697+
}
624698
}
625699
}

0 commit comments

Comments
 (0)