Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ODL library allows you to write enum values onto properties of other primitive types #3054

Open
gathogojr opened this issue Sep 4, 2024 · 1 comment
Labels

Comments

@gathogojr
Copy link
Contributor

gathogojr commented Sep 4, 2024

ODL library allows you to write enum values onto properties of other primitive types

Assemblies affected

  • Microsoft.OData.Core 7.x
  • Microsoft.OData.Core 8.x

Reproduce steps

Given the following data models:

public class Order
{
    public int Id { get; set; }
    public decimal Amount { get; set; }
    public DateTime OrderDate { get; set; }
}

public enum Color
{
    Black,
    White
}

The following code for writing an OData payload executes okay but produces an invalid output (included in the snippet as a comment):

var modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Order>("Orders");
modelBuilder.EnumType<Color>();

var model = modelBuilder.GetEdmModel();

var orderEntityType = model.SchemaElements.First(d => d.Name == "Order") as IEdmEntityType;
var ordersEntitySet = model.EntityContainer.FindEntitySet("Orders");

var messageWriterSettings = new ODataMessageWriterSettings
{
    EnableMessageStreamDisposal = false,
    Version = ODataVersion.V4,
    ODataUri = new ODataUri { ServiceRoot = new Uri("http://tempuri.org") }
};

var tempStream = new MemoryStream();

IODataResponseMessage asyncResponseMessage = new InMemoryMessage { Stream = tempStream };

await using (var messageWriter = new ODataMessageWriter(asyncResponseMessage, messageWriterSettings, model))
{
    var orderResource = new ODataResource
    {
        TypeName = typeof(Order).FullName,
        Id = new Uri("http://tempuri.org/Orders(1)"),
        Properties = new List<ODataProperty>
        {
            new ODataProperty { Name = "Id", Value = 1 },
            new ODataProperty { Name = "Amount", Value = Color.Black },
            new ODataProperty { Name = "OrderDate", Value = Color.White }
        }
    };

    var resourceWriter = await messageWriter.CreateODataResourceWriterAsync(ordersEntitySet, orderEntityType);

    await resourceWriter.WriteStartAsync(orderResource);
    await resourceWriter.WriteEndAsync();

    tempStream.Position = 0;
    var result = await new StreamReader(tempStream).ReadToEndAsync();

    // result:
    // {
    //     "@odata.context":"http://tempuri.org/$metadata#Orders/$entity",
    //     "@odata.id":"http://tempuri.org/Orders(1)",
    //     "Id":1,
    //     "Amount":"Black",
    //     "OrderDate":"White"
    // }
}

Expected result

The library should flag that the value being written onto the primitive property is invalid

Actual result

The library does not flag that the value being written onto the primitive property is invalid

Additional detail

Here's the definition of the InMemoryMessage type:

internal class InMemoryMessage : IODataResponseMessage, IODataResponseMessageAsync, IODataRequestMessage, IODataRequestMessageAsync        
{
    private readonly Dictionary<string, string> headers;

    public InMemoryMessage()
    {
        headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
    }

    public IEnumerable<KeyValuePair<string, string>> Headers
    {
        get { return this.headers; }
    }

    public int StatusCode { get; set; }

    public Uri Url { get; set; }

    public string Method { get; set; }

    public Stream Stream { get; set; }

    public string GetHeader(string headerName)
    {
        return this.headers.TryGetValue(headerName, out string headerValue) ? headerValue : null;
    }

    public void SetHeader(string headerName, string headerValue)
    {
        headers[headerName] = headerValue;
    }

    public Stream GetStream()
    {
        return this.Stream;
    }

    public Task<Stream> GetStreamAsync()
    {
        TaskCompletionSource<Stream> taskCompletionSource = new TaskCompletionSource<Stream>();
        taskCompletionSource.SetResult(this.Stream);
        return taskCompletionSource.Task;
    }
}
@gathogojr gathogojr added the bug label Sep 4, 2024
@gathogojr gathogojr changed the title ODL library allows you to write enum values onto properties of other primitive properties ODL library allows you to write enum values onto properties of other primitive types Sep 4, 2024
@marabooy marabooy added the P2 label Sep 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants