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

Ignoring Dictionary properties are not working #157

Open
komdil opened this issue Apr 27, 2021 · 13 comments
Open

Ignoring Dictionary properties are not working #157

komdil opened this issue Apr 27, 2021 · 13 comments

Comments

@komdil
Copy link

komdil commented Apr 27, 2021

I have two classes:

    public class Student : EntityBase
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
        public int Score { get; set; }
    }

    public abstract class EntityBase
    {
        public Dictionary<string, object> Test { get; set; }
        public Dictionary<string, object> Test2 { get; set; }
    }

My configuartion:

  static IEdmModel GetEdmModel()
        {
            var odataBuilder = new ODataConventionModelBuilder();
            odataBuilder.EntitySet<Student>("Student");
            var entity = odataBuilder.EntityType<Student>();
            entity.DerivesFrom<EntityBase>();
            entity.Ignore(s => s.Test);
            entity.Ignore(s => s.Test2);

            var baseEntity = odataBuilder.EntityType<EntityBase>();
            baseEntity.Abstract();
            baseEntity.Ignore(s => s.Test);
            baseEntity.Ignore(s => s.Test2);

            return odataBuilder.GetEdmModel();
        }

I am getting error on https://localhost:44383/odata/Student

System.ArgumentException: Found more than one dynamic property container in type 'Student'. Each open type must have at most one dynamic property container. (Parameter 'propertyInfo')
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddDynamicPropertyDictionary(PropertyInfo propertyInfo)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapTypes()
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.GetEdmModel()
   at Microsoft.AspNetCore.OData.Extensions.ActionDescriptorExtensions.GetEdmModel(ActionDescriptor actionDescriptor, HttpRequest request, Type entityClrType)
   at Microsoft.AspNetCore.OData.Query.ODataQueryParameterBindingAttribute.ODataQueryParameterBinding.BindModelAsync(ModelBindingContext bindingContext)
   at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BinderTypeModelBinder.BindModelAsync(ModelBindingContext bindingContext)
   at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value)
   at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<<CreateBinderDelegate>g__Bind|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.OData.Batch.ODataBatchMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

There should not be this error because I ignored dictionaries

xuzhg added a commit that referenced this issue Apr 27, 2021
@xuzhg
Copy link
Member

xuzhg commented Apr 27, 2021

@komdil Your route goes into non-odata routing.

It means your "GetEdmModel()" doesn't be called. Did you register any OData route?

From the call stack, it calls .ActionDescriptorExtensions.GetEdmModel(), it doesn't know how to ignore the two dictionary<string, object>.

I have a test for your issue, see 2c04d26

Use my sample, it works http://localhost:5000/odata/Student

{"@odata.context":"http://localhost:5000/odata/$metadata#Student","value":[{"Id":"abc","Name":"Zhangg","Score":8},{"Id":"efg","Name":"Jingchan","Score":8},{"Id":"xyz","Name":"Hollewye","Score":8}]}

@komdil
Copy link
Author

komdil commented May 4, 2021

@xuzhg I didn't understand the solution. Can you explain? It is not working on me.

@komdil
Copy link
Author

komdil commented May 4, 2021

I am getting this error on patching entity also. Here is call stack:

Each open type must have at most one dynamic property container. (Parameter 'propertyInfo')
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddDynamicPropertyDictionary(PropertyInfo propertyInfo)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapDerivedTypes(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapTypes()
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.GetEdmModel()
   at Microsoft.AspNetCore.OData.Extensions.ActionDescriptorExtensions.GetEdmModel(ActionDescriptor actionDescriptor, HttpRequest request, Type entityClrType)
   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.GetModel(Type elementClrType, HttpRequest request, ActionDescriptor actionDescriptor)
   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.GetODataQueryContext(Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)
   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.GetModelBoundPageSize(ActionExecutedContext actionExecutedContext, Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)
   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.OnActionExecuted(ActionExecutedContext actionExecutedContext, Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)
   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.OnActionExecuted(ActionExecutedContext actionExecutedContext)
   at Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute.OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Eagle.Framework.Server.Communications.OData.EagleODataMiddleware.TrackInvokeAsync(HttpContext httpContext) in C:\Repos\Eagle\Framework\Server\Eagle.Framework.Server.Communications.OData\EagleODataMiddleware.cs:line 108 System.ArgumentException: Found more than one dynamic property container in type 'IServerEntityBase'. Each open type must have at most one dynamic property container. (Parameter 'propertyInfo')
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddDynamicPropertyDictionary(PropertyInfo propertyInfo)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapDerivedTypes(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapType(StructuralTypeConfiguration edmType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.AddEntityType(Type type)
   at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddNavigationProperty(PropertyInfo navigationProperty, EdmMultiplicity multiplicity, Boolean containsTarget)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapTypes()
   at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.GetEdmModel()
   at Microsoft.AspNetCore.OData.Extensions.ActionDescriptorExtensions.GetEdmModel(ActionDescriptor actionDescriptor, HttpRequest request, Type entityClrType)
   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.GetModel(Type elementClrType, HttpRequest request, ActionDescriptor actionDescriptor)
   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.GetODataQueryContext(Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)
   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.GetModelBoundPageSize(ActionExecutedContext actionExecutedContext, Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)
   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.OnActionExecuted(ActionExecutedContext actionExecutedContext, Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)
   at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.OnActionExecuted(ActionExecutedContext actionExecutedContext)
   at Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute.OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)

@komdil
Copy link
Author

komdil commented May 5, 2021

@xuzhg Another way to reproduce this problem:
It is working only when I get entity by key.
Action:

public IActionResult Get(string key)
       {
           var student = CreateNewStudentWithGuid("Cody Allen", 130);
           return Ok(student);
       }

private static Student CreateNewStudentWithGuid(string name, int score)
       {
           return new Student
           {
               Id = new Guid("9DCC39C7-754C-4002-8627-BD719AA13E73"),
               Name = name,
               Score = score
           };
       }

It is working fine when my query is https://localhost:44383/Student/9DCC39C7-754C-4002-8627-BD719AA13E73
BUT it is not working when my query is https://localhost:44383/Student/Cody Allen
It is throwing this error:

System.ArgumentException: Found more than one dynamic property container in type 'Student'. Each open type must have at most one dynamic property container. (Parameter 'propertyInfo')
at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddDynamicPropertyDictionary(PropertyInfo propertyInfo)
at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapTypes()
at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.GetEdmModel()
at Microsoft.AspNetCore.OData.Extensions.ActionDescriptorExtensions.GetEdmModel(ActionDescriptor actionDescriptor, HttpRequest request, Type entityClrType)
at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.GetModel(Type elementClrType, HttpRequest request, ActionDescriptor actionDescriptor)
at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.GetODataQueryContext(Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)
at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.GetModelBoundPageSize(ActionExecutedContext actionExecutedContext, Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)
at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.OnActionExecuted(ActionExecutedContext actionExecutedContext, Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)
at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.OnActionExecuted(ActionExecutedContext actionExecutedContext)
at Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute.OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.OData.Batch.ODataBatchMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

HEADERS

Connection: keep-alive
Content-Type: application/json
Accept: /
Accept-Encoding: gzip, deflate, br
Host: localhost:44383
User-Agent: PostmanRuntime/7.28.0
Content-Length: 89
Postman-Token: bf70aec6-8ca0-42df-b907-e1affe7eb3d4

Here is my project source code: https://github.com/komdil/ODataCoreTest/tree/dynamicPropertyIssue

@xuzhg
Copy link
Member

xuzhg commented May 6, 2021

BUT it is not working when my query is https://localhost:44383/Student/Cody Allen

In this case, you should check the ModelState in the Get(Guid key) method before you do anything

image

There's an error showing that "The value 'Cody Allen' is not valid."

Of course, it's up to you without checking the model state. But, it's better to do model state check in every action.

By the way, if you do want it to work. you can add one line code as:

 public IActionResult Get(Guid key)
  {
            Request.ODataFeature().Model = Startup.GetEdmModel();
            var student = CreateNewStudentWithGuid("Cody Allen", 130);
            return Ok(student);
 } 

You can get:

image

But, this is not my solution for you to do it.

@komdil
Copy link
Author

komdil commented May 6, 2021

@xuzhg As you can see, parameter is not Guid key, it is string key. It can be primary key or alternative key of entity. It was working in previos version

@xuzhg
Copy link
Member

xuzhg commented May 6, 2021

Excuse me, i am confusing. Your code is "Guid key", not string key.

@komdil
Copy link
Author

komdil commented May 6, 2021

@xuzhg Another way to reproduce this problem:
It is working only when I get entity by key.
Action:

public IActionResult Get(string key)
       {
           var student = CreateNewStudentWithGuid("Cody Allen", 130);
           return Ok(student);
       }

private static Student CreateNewStudentWithGuid(string name, int score)
       {
           return new Student
           {
               Id = new Guid("9DCC39C7-754C-4002-8627-BD719AA13E73"),
               Name = name,
               Score = score
           };
       }

It is working fine when my query is https://localhost:44383/Student/9DCC39C7-754C-4002-8627-BD719AA13E73
BUT it is not working when my query is https://localhost:44383/Student/Cody Allen
It is throwing this error:

System.ArgumentException: Found more than one dynamic property container in type 'Student'. Each open type must have at most one dynamic property container. (Parameter 'propertyInfo')
at Microsoft.OData.ModelBuilder.StructuralTypeConfiguration.AddDynamicPropertyDictionary(PropertyInfo propertyInfo)
at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapStructuralType(StructuralTypeConfiguration structuralType)
at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.MapTypes()
at Microsoft.OData.ModelBuilder.ODataConventionModelBuilder.GetEdmModel()
at Microsoft.AspNetCore.OData.Extensions.ActionDescriptorExtensions.GetEdmModel(ActionDescriptor actionDescriptor, HttpRequest request, Type entityClrType)
at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.GetModel(Type elementClrType, HttpRequest request, ActionDescriptor actionDescriptor)
at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.GetODataQueryContext(Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)
at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.GetModelBoundPageSize(ActionExecutedContext actionExecutedContext, Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)
at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.OnActionExecuted(ActionExecutedContext actionExecutedContext, Object responseValue, IQueryable singleResultCollection, ControllerActionDescriptor actionDescriptor, HttpRequest request)
at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.OnActionExecuted(ActionExecutedContext actionExecutedContext)
at Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute.OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.OData.Batch.ODataBatchMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

HEADERS

Connection: keep-alive
Content-Type: application/json
Accept: /
Accept-Encoding: gzip, deflate, br
Host: localhost:44383
User-Agent: PostmanRuntime/7.28.0
Content-Length: 89
Postman-Token: bf70aec6-8ca0-42df-b907-e1affe7eb3d4

Here is my project source code: https://github.com/komdil/ODataCoreTest/tree/dynamicPropertyIssue

@xuzhg Look here please. Also I pushed new changes on https://github.com/komdil/ODataCoreTest/tree/dynamicPropertyIssue

@xuzhg
Copy link
Member

xuzhg commented May 6, 2021

@komdil Actually, That's not related to the type of parameter in Get() action, that's related to Edm type of student "id" property.

If you send ~/$metadata, you can see it's a Edm.Guid type.

If it's a string type, the formatter for string type is "singe quote" + content + "single quote".

So, I assume even you change as "string key" in Get() method, it still can't work. Cody Allen is not a valid Guid, it's also not a valid string. 'Cody Allen' is a valid string.

@komdil
Copy link
Author

komdil commented May 6, 2021

@xuzhg Here is my meta data:


<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
    <edmx:DataServices>
        <Schema Namespace="ODataCoreTest" xmlns="http://docs.oasis-open.org/odata/ns/edm">
            <EntityType Name="EntityBase" Abstract="true" />
            <EntityType Name="Student" BaseType="ODataCoreTest.EntityBase">
                <Key>
                    <PropertyRef Name="Id" />
                </Key>
                <Property Name="Id" Type="Edm.Guid" Nullable="false" />
                <Property Name="Name" Type="Edm.String" />
                <Property Name="Score" Type="Edm.Int32" Nullable="false" />
                <Annotation Term="OData.Community.Keys.V1.AlternateKeys">
                    <Collection>
                        <Record Type="OData.Community.Keys.V1.AlternateKey">
                            <PropertyValue Property="Key">
                                <Collection>
                                    <Record Type="OData.Community.Keys.V1.PropertyRef">
                                        <PropertyValue Property="Alias" String="Name" />
                                        <PropertyValue Property="Name" PropertyPath="Name" />
                                    </Record>
                                </Collection>
                            </PropertyValue>
                        </Record>
                    </Collection>
                </Annotation>
            </EntityType>
        </Schema>
        <Schema Namespace="Default" xmlns="http://docs.oasis-open.org/odata/ns/edm">
            <EntityContainer Name="Container">
                <EntitySet Name="Student" EntityType="ODataCoreTest.Student" />
            </EntityContainer>
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>

As you can it has alternetive key. It was working in previos version. Now it is not working even with valid string:

https://localhost:44383/Student(Name='Cody Allen')
https://localhost:44383/Student('Cody Allen')
https://localhost:44383/Student/'Cody Allen'

@xuzhg
Copy link
Member

xuzhg commented May 6, 2021

@komdil Oh, now, I see.

Unfortunately, It's not implemented for the alternate key in conventional or attribute routing in 8.0.
I hope I can implement it before RTM. But, I can't guarantee.

@komdil
Copy link
Author

komdil commented May 6, 2021

@xuzhg Is there any workarround ?

@xuzhg
Copy link
Member

xuzhg commented May 6, 2021

Let me test it tomorrow and see whether I can raise the priority for alternate key.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants