OData / OData/AspNetCoreOData

Model aliasing doesn't work when not using DataContract and DataMember attributes

Open
#278 2 comments 0 reactions 1 assignee View on GitHub

@xuzhg is already working on this.

Since Aug 17, 2021.

followup investigated
Dominant language
C#
Stars
505
Forks
186
PR merge metrics
No merged PRs in 30d

Description

I was trying to add OData query options support with model aliasing to an ASP.NET Core API project without using OData routing.

Assemblies affected
  • Microsoft.AspNetCore.OData 8.0.1
  • Microsoft.OData.ModelBuilder 1.0.6
Reproduce steps
  1. Registering the OData services

    // Api/Startup.cs
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddControllers().AddOData(options =>
                {
                    options
                        .AddRouteComponents(GetEdmModel())
                        .Filter()
                        .OrderBy()
                        .SetMaxTop(100)
                        .EnableNoDollarQueryOptions = true;
                });
    
  2. Building the EDM model

    // Api/Startup.cs
            private static IEdmModel GetEdmModel()
            {
                var builder = new ODataConventionModelBuilder();
                var account = builder.EntityType<Core.Models.Account>();
                account.Property(e => e.Code).Name = "code";
                account.Property(e => e.Name).Name = "name";
                return builder.GetEdmModel();
            }
    
    // Core/Models/Account.cs
    namespace Core.Models
    {
        public class Account
        {
            public string Code { get; set; }
    
            public string Name { get; set; }
        }
    }
    
  3. Creating the controller

    // Api/Controllers/AccountsController
        public class AccountsController : ControllerBase
        {
            [HttpGet]
            public async Task<IEnumerable<Api.Models.Account>> Get(
                ODataQueryOptions<Core.Models.Account> options,
                CancellationToken cancellationToken = default)
            {
                var coreModels = await Service.ListAsync(options, cancellationToken);
                return Mapper.Map<IEnumerable<Api.Models.Account>>();
            }
        }
    
  4. Execute a GET request (simplified and formatted for clarity)

    GET /accounts
        ?filter=code eq 'F4'
        &orderby=name
    
Expected result

A list of accounts.

Actual result
Microsoft.OData.ODataException: Could not find a property named 'name' on type 'Core.Models.Account'.
Additional detail

When I switched to using the DataContext and DataMember attributes, everything worked as expected. However, this is not an option as it causes the Core layer to depend on the API layer.

// Api/Startup.cs
        private static IEdmModel GetEdmModel()
        {
            var builder = new ODataConventionModelBuilder();
            builder.EntityType<Core.Models.Account>();
            return builder.GetEdmModel();
        }

// Core/Models/Account.cs
namespace Core.Models
{
    [DataContract]
    public class Account
    {
        [DataMember(Name = "code")]
        public string Code { get; set; }

        [DataMember(Name = "name")]
        public string Name { get; set; }
    }
}

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.