Reputation: 107
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
Response received to the client side is below, but **Collection properties are missing in response **
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
Upvotes: 2
Views: 629
Reputation: 107
I could achieved the described requirement as below.
Added [AutoExpand] attribute to Collection properties
//Model classes
public class ApplicationUserViewModel
{
//Other properties...
[AutoExpand]
public virtual ICollection<ApplicationUserDepartmentViewModel>? UserDepartments { get; set; }
}
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