OData / OData/WebApi

OData 7.4 aspnet core 3.1 Formatter Issues

Open
#2,139 3 comments 1 reaction 1 assignee View on GitHub

@xuzhg is already working on this.

Since Apr 28, 2020.

investigating
Dominant language
C#
Stars
864
Forks
467
PR merge metrics
No merged PRs in 30d

Description

Hey everyone. I am having some strange issues using custom formatters for odata 7.4 in aspnetcore 3.1 web api project.

Here are the full details of the issue, hopefully someone will be able to help :

https://stackoverflow.com/questions/61450358/custom-odata-formatter-for-netcore-3-1-webapi-issues

So i am building a service that has to be consumed through OData and i am having a really difficult time figuring how to add custom formatters to it. I need my OData serializer to ignore null values when serializing data. I have created these 2 to achieve that :

public class SmartODataSerializerProvider : DefaultODataSerializerProvider
{
    private readonly SmartODataEntityTypeSerializer _entityTypeSerializer;

    public SmartODataSerializerProvider(IServiceProvider rootContainer)
        : base(rootContainer)
    {
        _entityTypeSerializer = new SmartODataEntityTypeSerializer(this);
    }

    public override ODataEdmTypeSerializer GetEdmTypeSerializer(Microsoft.OData.Edm.IEdmTypeReference edmType)
    {
        // Support for Entity types AND Complex types
        if (edmType.Definition.TypeKind == EdmTypeKind.Entity || edmType.Definition.TypeKind == EdmTypeKind.Complex)
            return _entityTypeSerializer;
        else
            return base.GetEdmTypeSerializer(edmType);
    }
}

And

public class SmartODataEntityTypeSerializer : ODataResourceSerializer
{
    public SmartODataEntityTypeSerializer(ODataSerializerProvider provider)
        : base(provider) { }

    /// <summary>
    /// Only return properties that are not null
    /// </summary>
    /// <param name="structuralProperty">The EDM structural property being written.</param>
    /// <param name="resourceContext">The context for the entity instance being written.</param>
    /// <returns>The property be written by the serilizer, a null response will effectively skip this property.</returns>
    public override Microsoft.OData.ODataProperty CreateStructuralProperty(Microsoft.OData.Edm.IEdmStructuralProperty structuralProperty, ResourceContext resourceContext)
    {
        var property = base.CreateStructuralProperty(structuralProperty, resourceContext);
        return property.Value != null ? property : null;
    }
}

These were provided on another stack overflow question. However, the issue arises when i try to use this serializer. I already have an odata endpoint that's working (it just serializes everything with null) and when i apply the following configuration to it i keep getting '404 Not Found' on the same EP that works without it.

app.UseEndpoints(endpoints =>
        {
            endpoints.MapODataRoute("odata", "odata", a =>
            {
                a.AddService(Microsoft.OData.ServiceLifetime.Singleton, typeof(IEdmModel), sp => GetEdmModel(app.ApplicationServices));
                a.AddService(Microsoft.OData.ServiceLifetime.Singleton, typeof(ODataSerializerProvider), sp => new SmartODataSerializerProvider(sp));
            });
            endpoints.EnableDependencyInjection();
            //endpoints.MapODataRoute("odata", "odata", GetEdmModel(app.ApplicationServices));
            endpoints.MapControllers();
        }); 

This is the endpoints settings. I commented out the line that makes it work but without custom formatters. Here's the IEdmModel function used in the setup :

 private static IEdmModel GetEdmModel(IServiceProvider services)
    {
        ODataConventionModelBuilder builder = new ODataConventionModelBuilder(services);

        builder.Namespace = "RS";
        builder.EntitySet<PropertyIndexODataModel>("Properties");
        builder.EntitySet<ReportResultModel>("Reports");

        var function = builder.EntityType<ReportResultModel>().Collection.Function("Generate");

        function.Parameter<int>("listId");
        function.CollectionParameter<string>("functionsToRun");
        function.ReturnsCollectionFromEntitySet<ReportResultModel>("Reports");

        return builder.GetEdmModel();
    }

So when i apply this odataroute i keep getting the 404. When i remove it and go back to 'endpoints.MapODataRoute("odata", "odata", GetEdmModel(app.ApplicationServices));' it works without problems.

This seems like a very trivial thing but i searched everywhere and i still couldn't get it to work. I am using OData 7.4 and netcore 3.1. Thanks in advance!

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.