I am trying to get breeze to work with my webapi in combination with entity framework but seem to be stuck when i try to query a certain entity that is using a custom enum.
I am using the breeze EDMbuilder to generate the edm model for my metadata.
My config:
config.Routes.MapODataServiceRoute(
routeName: "odata",
routePrefix: "odata",
model: EdmBuilder.GetEdm<Base.DAL.Entities.DbContextFixForEdm>(),
batchHandler: new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer)
);
The metadata is generated and if i query odata/$metadata i see all of my entities with their properties.
Now the problem i am facing is as follows.
I have a very basic entity called ApiUserEntity with the following properties:
public class ApiUserEntity : BaseEntity
{
public string Username { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public string Salt { get; set; }
public ApiUserRole Role { get; set; }
public ApiPermission Permission { get; set; }
}
And a simple Odatacontroller get function which returns an iqueryable of ApiUserEntities:
// GET: odata/ApiUsers
[EnableQuery]
public IQueryable<ApiUserEntity> GetApiUsers(ODataQueryOptions<ApiUserEntity> opts)
{
return _userService.GetUsers();
}
However whenever i query this method i always get back the following error:
'Base.DAL.Entities.ApiUserRole' cannot be serialized using the ODataMediaTypeFormatter.
This error is not just when i query it with breeze but also when i acces the method from my browser.
In the metadata file generated the apiuserentity looks like this:
<EntityType xmlns:p5="http://schemas.microsoft.com/ado/2013/11/edm/customannotation" Name="ApiUserEntity" p5:ClrType="Base.DAL.Entities.ApiUserEntity, Base.DAL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<Key>
<PropertyRef Name="Id"/>
</Key>
<Property xmlns:p7="http://schemas.microsoft.com/ado/2009/02/edm/annotation" Name="Id" Type="Edm.Int32" Nullable="false" p7:StoreGeneratedPattern="Identity"/>
<Property Name="Username" Type="Edm.String" Nullable="false" MaxLength="255" FixedLength="false" Unicode="true"/>
<Property Name="Password" Type="Edm.String" Nullable="false" MaxLength="300" FixedLength="false" Unicode="true"/>
<Property Name="Email" Type="Edm.String" Nullable="false" MaxLength="255" FixedLength="false" Unicode="true"/>
<Property Name="Salt" Type="Edm.String" MaxLength="255" FixedLength="false" Unicode="true"/>
<Property Name="Role" Type="Base.DAL.Entities.ApiUserRole" Nullable="false"/>
<Property Name="Permission" Type="Base.DAL.Entities.ApiPermission" Nullable="false"/>
<Property Name="CreatedAt" Type="Edm.DateTime"/>
<NavigationProperty Name="Domains" Relationship="Base.DAL.Entities.DomainEntity_Users" ToRole="DomainEntity_Users_Source" FromRole="DomainEntity_Users_Target"/>
</EntityType>
The main thing i noticed is that it is adding an Edm prefix to common types like strings and datetime. But my custom enums are just their full namespace. When i change the properties of custom enums to int it will give me back results but i would really want to use these enums and turning them into ints would not be a solution.
I am geussing it cant find the type and doesnt know how to parse it but that is just geussing. Other than that i have no idea how to solve it or where i should go from here. Have been banging my head over this for the last couple of hours without result.
I use the following classes to build the Edm Model:
public class ApiUserEntity // : BaseEntity
{
public int Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public string Salt { get; set; }
public ApiUserRole Role { get; set; }
public ApiPermission Permission { get; set; }
}
public enum ApiUserRole
{
Admin,
Guest
}
public enum ApiPermission
{
Write,
Read,
WriteRead
}
Here's the metadata document:
<?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="WebApplication1.Models" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityType Name="ApiUserEntity">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="Edm.Int32" Nullable="false" />
<Property Name="Username" Type="Edm.String" />
<Property Name="Password" Type="Edm.String" />
<Property Name="Email" Type="Edm.String" />
<Property Name="Salt" Type="Edm.String" />
<Property Name="Role" Type="WebApplication1.Models.ApiUserRole" Nullable="false" />
<Property Name="Permission" Type="WebApplication1.Models.ApiPermission" Nullable="false" />
</EntityType>
<EnumType Name="ApiUserRole">
<Member Name="Admin" Value="0" />
<Member Name="Guest" Value="1" />
</EnumType>
<EnumType Name="ApiPermission">
<Member Name="Write" Value="0" />
<Member Name="Read" Value="1" />
<Member Name="WriteRead" Value="2" />
</EnumType>
</Schema>
<Schema Namespace="Default" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityContainer Name="Container">
<EntitySet Name="ApiUserEntitys" EntityType="WebApplication1.Models.ApiUserEntity" />
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
Custom enum types with their full namespace is correct. I think your problem is your method definition. Please try to modify your method as:
[EnableQuery]
public IQueryable<ApiUserEntity> GetApiUsers()
{
return _userService.GetUsers();
}
That is, don't writeEnableQueryAttribute
and ODataQueryOptions<ApiUserEntity> opts
for a method at the same time.
After modification, here's my sample test:
GET ~/odata/ApiUserEntitys
{
"@odata.context":"http://localhost:40502/odata/$metadata#ApiUserEntitys","value":[
{
"Id":1,"Username":"UserName #1","Password":"Password #1","Email":"Email #1","Salt":"Salt E1","Role":"Admin","Permission":"WriteRead"
},{
"Id":2,"Username":"UserName #2","Password":"Password #2","Email":"Email #2","Salt":"Salt E2","Role":"Admin","Permission":"WriteRead"
},{
"Id":3,"Username":"UserName #3","Password":"Password #3","Email":"Email #3","Salt":"Salt E3","Role":"Admin","Permission":"WriteRead"
},{
"Id":4,"Username":"UserName #4","Password":"Password #4","Email":"Email #4","Salt":"Salt E4","Role":"Admin","Permission":"WriteRead"
},{
"Id":5,"Username":"UserName #5","Password":"Password #5","Email":"Email #5","Salt":"Salt E5","Role":"Admin","Permission":"WriteRead"
}
]
}
Hope it can help you. Thanks.