Aruna101
Aruna101

Reputation: 107

.NET core OData web API PATCH/POST request - complex properties missing in response

I have a requirement to return the entire updated entity from .net core OData web API after executing a PATCH/POST request. But with below code, I'm getting response object containing only primitive type properties. Complex type properties are not returned. For GET requests, there is $expand option. But not for PATCH/POST.

//AddOData
services.AddControllers()
 .AddOData(
    options =>
    {
        options.AddRouteComponents("odata", ODataModelBuilderExt.BuildModels());
        options.Select().OrderBy().Expand().Count().Filter().SetMaxTop(null);
    });


//Edm ModelBuilder
        public static IEdmModel BuildModels()
        {
            ODataConventionModelBuilder modelBuilder = new ODataConventionModelBuilder();

            modelBuilder.EntitySet<ApplicationUserViewModel>("ApplicationUser");
            modelBuilder.EntitySet<ApplicationUserDepartmentViewModel>("Department");

            return modelBuilder.GetEdmModel();
        }

//Model classes
    public class ApplicationUserViewModel
    {
        public int? Id { get; set; }
        public string FirstName { get; set; } = string.Empty;
        public string LastName { get; set; } = string.Empty;
        public string Email { get; set; } = string.Empty;
        public string PhoneNumber { get; set; } = string.Empty;
        public string Token{ get; set; } = string.Empty;
        public UserAccountActiveState UserAccountActiveState { get; set; }

        public virtual ICollection<ApplicationUserDepartmentViewModel>? UserDepartments { get; set; }
    }


//Controller Action method

    public class ApplicationUserController : ODataController
    {
        [HttpPatch]
        public async Task<IActionResult> Patch([FromRoute] int key, [FromBody] Delta<ApplicationUserViewModel> delta)
        {

            //Processing code removed...
            
            //Returning entity after processing PATCH operation
            ApplicationUserViewModel? dtoUpdated = await applicationUserService.Patch(key, delta);

            if (dtoUpdated == null)
            {
                return NotFound();
            }

            return Updated(dtoUpdated);
        }
    }

How ApplicationUserViewModel looks when debug in controller enter image description here

Response received to the client side is below, but **Collection properties are missing in response ** enter image description here

I'm seeking help to find out the reason why complex properties are dropped in response. How can I return them in response (and to set it as default behavior) Tried setting request http header "Prefer" with 'return=representation' with no success.

Further I noted, if I return the same object anonymously, the collection properties are being serialized and retuned in response as below.

...
            return Updated(new 
            {
                Id = key,
                //.......
                UserDepartments = new List<ApplicationUserDepartmentViewModel>()
                {
                    new ApplicationUserDepartmentViewModel()
                    {
                         Id = 5,
                         Name = "Dpt"
                    }
                },
            });
...

But when ApplicationUserViewModel is returned as below, collection type properties are dropped.

return Updated(new ApplicationUserViewModel()
  {
   //....
  });

Complete request/response headers for information enter image description here

Upvotes: 2

Views: 629

Answers (1)

Aruna101
Aruna101

Reputation: 107

I could achieved the described requirement as below.

  1. Added [AutoExpand] attribute to Collection properties

     //Model classes
     public class ApplicationUserViewModel
     {
        //Other properties...
    
        [AutoExpand]
        public virtual ICollection<ApplicationUserDepartmentViewModel>? UserDepartments { get; set; }
     }
    
  2. Return Entity from the action method, not the Updated(entity).

     [HttpPatch]
     [EnableQuery]
     public async Task<ApplicationUserViewModel> Patch([FromRoute] int key, [FromBody] Delta<ApplicationUserViewModel> delta)
     {
         if (delta == null)
         {
             throw new AppModalValidationException(ModelState);
         }
    
         ValidationResult result = await validator.ValidateAsync(delta.GetInstance());
         if (!result.IsValid)
         {
             result.AddToModelState(ModelState);
         }
    
         if (!ModelState.IsValid)
         {
             throw new AppModalValidationException(ModelState);
         }
    
         ApplicationUserViewModel dtoUpdated = await applicationUserService.Patch(key, delta);
    
         return dtoUpdated;
    
     }
    

OData response serializer will take care of the rest of expand property handling. Note : The properties decorated with [AutoExpand] will be automatically included in response even it is not provided in request.

Upvotes: 0

Related Questions