Open mikepizzo opened 4 years ago
@mikepizzo @paulodero @WanjohiSammy The WritePrimitiveAsync
method is a convenience method that one can use to write a single-valued primitive properties.
To write collection-valued primitive properties as well as single-valued and collection-valued enum properties, one can use the WriteStart/WriteStartAsync(ODataPropertyInfo)
method.
The method can take an ODataProperty
object and will handle the writing correctly.
Here's how we can write a single-valued and a collection-valued enum property:
public async Task WriteEnumAsync()
{
var tempServiceUri = "http://tempuri.org";
var tempModel = new EdmModel();
var tempEnumType = new EdmEnumType("NS", "Color");
tempEnumType.AddMember("Black", new EdmEnumMemberValue(0));
tempEnumType.AddMember("White", new EdmEnumMemberValue(1));
tempModel.AddElement(tempEnumType);
var tempEntityType = tempModel.AddEntityType("NS", "Entity");
tempEntityType.AddKeys(tempEntityType.AddStructuralProperty("Id", EdmCoreModel.Instance.GetInt32(false)));
tempEntityType.AddStructuralProperty("EnumProp",
new EdmEnumTypeReference(tempEnumType, false));
tempEntityType.AddStructuralProperty("EnumCollectionProp",
new EdmCollectionTypeReference(new EdmCollectionType(new EdmEnumTypeReference(tempEnumType, false))));
var tempEntityContainer = tempModel.AddEntityContainer("Default", "Container");
var tempEntitySet = tempEntityContainer.AddEntitySet("Entities", tempEntityType);
var tempResource = new ODataResource
{
TypeName = "NS.Entity"
};
var tempMessageWriterSettings = new ODataMessageWriterSettings
{
Version = ODataVersion.V4,
EnableMessageStreamDisposal = false,
BaseUri = new Uri(tempServiceUri),
ODataUri = new ODataUri { ServiceRoot = new Uri(tempServiceUri) }
};
await using (var tempStream = new MemoryStream())
{
IODataResponseMessage tempResponseMessage = new InMemoryMessage { Stream = tempStream };
await using (var tempMessageWriter = new ODataMessageWriter(tempResponseMessage, tempMessageWriterSettings))
{
var tempResourceWriter = await tempMessageWriter.CreateODataResourceWriterAsync(tempEntitySet, tempEntityType);
await tempResourceWriter.WriteStartAsync(tempResource);
await tempResourceWriter.WriteStartAsync(
new ODataPropertyInfo { Name = "Id" });
await tempResourceWriter.WritePrimitiveAsync(new ODataPrimitiveValue(1));
await tempResourceWriter.WriteEndAsync();
await tempResourceWriter.WriteStartAsync(
new ODataProperty { Name = "EnumProp", Value = new ODataEnumValue("Black ") });
await tempResourceWriter.WriteEndAsync();
await tempResourceWriter.WriteStartAsync(
new ODataProperty { Name = "EnumCollectionProp", Value = new ODataCollectionValue { Items = [new ODataEnumValue("White "), new ODataEnumValue("Black ")] } });
await tempResourceWriter.WriteEndAsync();
await tempResourceWriter.WriteEndAsync();
}
tempStream.Position = 0;
var tempPayload = await new StreamReader(tempStream).ReadToEndAsync();
}
}
We don't have a feature gap here.
A method that accepts an ODataEnumValue
and another method that accepts an ODataCollectionValue
(to support writing primitive and enum collection-valued properties) would be an enhancement.
This should be a P3 IMO.
You are right that the repro was a simplified example that could be written as a property. However, it was intended to be a simple example.
The streaming functionality was added in order to support scenarios where data was read from one source and written to the wire without holding data in memory. In particular, writing large objects with large collections.
In particular, I can start writing a collection and then write values within that collection. If the collection contains enums (either it is typed as a collection of enums, a collection of primitive types, or an untyped collection) then I cannot write it in a streamed fashion -- I have to construct the ODataCollectionValue, as per your example.
So the functionality gap is not being able to stream collections that may contain enum values (and, for streaming primitive/untyped collections I may not know before I start writing if it contains an enum)
It is also unfortunate to have to handle enums differently than other types, but that's not the feature gap -- the feature gap is being able to stream collections that may contain enums.
For streaming support, we added the ability to write individual properties of a resource, as well as individual primitive values within a collection, by calling WritePrimitive. Similarly, we added a ReadState .Primitive for reading primitive values. Unfortunately, enum values are not considered primitive values, so we need to add a way to read/write individual enum properties and values within a collection.
Assemblies affected
OData .Net lib 7.6.3
Reproduce steps
You can write an individual string property as follows:
Similar patterns exist for writing a primitive value within a collection and for reading primitive properties/primitive values within a collection.
Expected result
There should be similar patterns for writing/reading an enum property, or value within a collection
Actual result
There is no equivalent for reading/writing an enum property, or value within a collection.