AspNetCoreOData
AspNetCoreOData copied to clipboard
OData Wrapper gets lost on projection
Assemblies affected ASP.NET Core OData 8.x (latest)
Describe the bug When applying own projection/select to the query the odata wrapper get's lost.
Reproduce steps
public ActionResult<IQueryable> Get(ODataQueryOptions<ArticleInfo> odata)
{
var query = DbContext.ArticleInfos.FromSqlRaw("select 'abc' as Id, 'somevalue' as Value union select 'xyz','othervalue'");
var newQuery = odata.ApplyTo(query);
// this line eliminates OData wrapper
var finalQuery = newQuery.Cast<ArticleInfo>().Select(a => new { a.Value });
return Ok(finalQuery);
}
Data Model
public class ArticleInfo
{
[Key]
public string Id { get; set; }
public string Value{ get; set; }
}
EDM (CSDL) Model
<EntityType Name="ArticleInfo">
<Key>
<PropertyRef Name="Id"/>
</Key>
<Property Name="Id" Type="Edm.String" Nullable="false"/>
<Property Name="Value" Type="Edm.String"/>
</EntityType>
Request/Response
GET Request
ArticleInfos?$filter=Id%20eq%20%27abc%27
Response
[{"Value":"somevalue"}]
Expected behavior
Should be this response:
{"@odata.context":"https://localhost:7188/coreservices/odata/$metadata#ArticleInfos(Value)","value":[{"Value":"somevalue"}]}
@audacity76
var finalQuery = newQuery.Cast<ArticleInfo>().Select(a => new { a.Value }); it returns an anonymous type that is not defined in the OData model. So, OData output formatter can't be selected based on this anonymous type, it goes to other formatter.
It looks like you want to get partition data, why don't you use '$select=Value' ?
Thanks for your response @xuzhg!
There are other actions involved (which I skipped for simplicity). So, $select is not an option in my case. Any way to get the output formatter running?
Some ways at quick glace (no guarantee)
- create an intermediate type and use it in
Select(a => new YourType { Value = a.Value} ), but it could change the context uri. - manually use "$select=Value" in your controller/action, parse it using ODataQueryOptionParsers (or build the SelectExpandClause manually), build another ODataQueryOption, then, apply to the data.
- Customize ODataOutputFormmatter by deriving it and override the 'CanWrite' and other virtual methods.