AspNetCoreOData icon indicating copy to clipboard operation
AspNetCoreOData copied to clipboard

Modify OData API response after OData is executed

Open jiangyi1985 opened this issue 2 years ago • 5 comments

How do I modify the result data of an OData API?

For example, in the response of a list OData API, we want to set some property to null.

I tried to do it in IResultFilter.OnResultExecuted like this:

    public class MyResultFilter : Attribute, IResultFilter
    {
        public void OnResultExecuted(ResultExecutedContext context)
        {
            var result = context.Result as OkObjectResult;
            var data = result.Value as EntityQueryable<Microsoft.AspNetCore.OData.Query.Wrapper.SelectAllAndExpand<DbContext.Table1>>;

            //modify data
        }
    }

    [EnableQuery]
    [MyResultFilter]
    public IActionResult Get()
    {
        var querable = DbContext.Table1.AsQueryable<Table1>();
        return Ok(querable);
    }

But the SelectAllAndExpand is internal so the code won't compile.

Is there a better way to do this?

jiangyi1985 avatar Jun 07 '22 03:06 jiangyi1985

...in the response of a list OData API, we want to set some property to null.

Would you mind elaborating a bit on why you need such weird requirement?

If you don't want your API surface to reflect your internal model but something else (like a DTO), then I'd suggest using AutoMapper.Extensions.OData to achieve that by decoupling the models and performing the mapping you want.

julealgon avatar Jun 07 '22 13:06 julealgon

@jiangyi1985 if what you are doing is something simple then you can make the changes in the controller method. Otherwise, you need to create a custom serializer and serializer provider to set the properties that you want set to null. You can look at this example on how to create custom serializers.

https://github.com/xuzhg/WebApiSample/tree/main/CustomSerializerSample

ElizabethOkerio avatar Jun 07 '22 18:06 ElizabethOkerio

...in the response of a list OData API, we want to set some property to null.

Would you mind elaborating a bit on why you need such weird requirement?

If you don't want your API surface to reflect your internal model but something else (like a DTO), then I'd suggest using AutoMapper.Extensions.OData to achieve that by decoupling the models and performing the mapping you want.

We are just trying to remove some sensitive info, depending on some condition.

For example, for the result of an OData API of a list of user reviews:

foreach(var r in reviews)
{
    if(r.IsAnonymousSubmission)
        r.SubmitterName = "";
}

We tried adding AutoMapper config CreateMap<Table1, Table1> and then in our action: return Ok(DbContext.Table1.GetQuery(_mapper, options));

But we got an exception: System.ArgumentException: 'Member virtual_property, does not exists in type DbContext.Table1.' where virtual_property is an EF relationship property on Table1

Does AutoMapper work if we have EF Relationship and we are using OData expand? Or if it's a config problem?

jiangyi1985 avatar Jun 08 '22 03:06 jiangyi1985

@jiangyi1985 if what you are doing is something simple then you can make the changes in the controller method. Otherwise, you need to create a custom serializer and serializer provider to set the properties that you want set to null. You can look at this example on how to create custom serializers.

https://github.com/xuzhg/WebApiSample/tree/main/CustomSerializerSample

thanks we will look into this solution

jiangyi1985 avatar Jun 08 '22 07:06 jiangyi1985

Does AutoMapper work if we have EF Relationship and we are using OData expand? Or if it's a config problem?

It does work with expands on the mapped type. I've never made a X to X mapping with this setup though, not sure if that could be the cause of your issue.

Have you considered creating a separate DTO model without the sensitive info in it and mapping to that instead?

julealgon avatar Jun 08 '22 16:06 julealgon