I'm pretty new to OData and WebAPI 2. Sorry ahead of time.
My goal is to use an OData service which has a WcfService
object and a WcfClient
object exposed, and associate the WcfClient
with the WcfService
through a list property Clients
. (eg. service.Clients.Add(client)
but using an OData service)
I have an EF code first database with WcfService
, WcfClient
, and SoaApplication
classes. And, an OData webservice setup with Microsoft.AspNet.WebApi.OData 5.1.1. The code linking everything is all setup using the wizards in VS2013. The $metadata for the OData endpoint looks like this (http://soa.local.xxx/odata/$metadata
):
<edmx:Edmx xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx" Version="1.0">
<edmx:DataServices xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:DataServiceVersion="3.0" m:MaxDataServiceVersion="3.0">
<Schema xmlns="http://schemas.microsoft.com/ado/2009/11/edm" Namespace="xxx">
<EntityType Name="SoaApplication">
<Key>
<PropertyRef Name="ApplicationId"/>
</Key>
<Property Name="ApplicationId" Type="Edm.Int32" Nullable="false"/>
<Property Name="ComputerName" Type="Edm.String"/>
<Property Name="ConfigLocation" Type="Edm.String"/>
</EntityType>
<EntityType Name="WcfClient">
<Key>
<PropertyRef Name="ClientId"/>
</Key>
<Property Name="ClientId" Type="Edm.Int32" Nullable="false"/>
<Property Name="ApplicationId" Type="Edm.Int32" Nullable="false"/>
<Property Name="Address" Type="Edm.String"/>
<Property Name="Binding" Type="Edm.String"/>
<Property Name="BindingConfiguration" Type="Edm.String"/>
<Property Name="Contract" Type="Edm.String"/>
<NavigationProperty Name="Application" Relationship="xxx.xxx_WcfClient_Application_xxx_SoaApplication_ApplicationPartner" ToRole="Application" FromRole="ApplicationPartner"/>
</EntityType>
<EntityType Name="WcfService">
<Key>
<PropertyRef Name="ServiceId"/>
</Key>
<Property Name="ServiceId" Type="Edm.Int32" Nullable="false"/>
<Property Name="ApplicationId" Type="Edm.Int32" Nullable="false"/>
<Property Name="AddressNoScheme" Type="Edm.String"/>
<Property Name="AddressForMatching" Type="Edm.String"/>
<Property Name="Binding" Type="Edm.String"/>
<Property Name="BindingConfiguration" Type="Edm.String"/>
<Property Name="Contract" Type="Edm.String"/>
<NavigationProperty Name="Application" Relationship="xxx.xxx_WcfService_Application_xxx_SoaApplication_ApplicationPartner" ToRole="Application" FromRole="ApplicationPartner"/>
<NavigationProperty Name="Clients" Relationship="xxx.xxx_WcfService_Clients_xxx_WcfClient_ClientsPartner" ToRole="Clients" FromRole="ClientsPartner"/>
</EntityType>
<Association Name="xxx_WcfClient_Application_xxx_SoaApplication_ApplicationPartner">
<End Type="xxx.SoaApplication" Role="Application" Multiplicity="0..1"/>
<End Type="xxx.WcfClient" Role="ApplicationPartner" Multiplicity="0..1"/>
</Association>
<Association Name="xxx_WcfService_Application_xxx_SoaApplication_ApplicationPartner">
<End Type="xxx.SoaApplication" Role="Application" Multiplicity="0..1"/>
<End Type="xxx.WcfService" Role="ApplicationPartner" Multiplicity="0..1"/>
</Association>
<Association Name="xxx_WcfService_Clients_xxx_WcfClient_ClientsPartner">
<End Type="xxx.WcfClient" Role="Clients" Multiplicity="*"/>
<End Type="xxx.WcfService" Role="ClientsPartner" Multiplicity="0..1"/>
</Association>
</Schema>
<Schema xmlns="http://schemas.microsoft.com/ado/2009/11/edm" Namespace="Default">
<EntityContainer Name="Container" m:IsDefaultEntityContainer="true">
<EntitySet Name="SoaApplication" EntityType="xxx.SoaApplication"/>
<EntitySet Name="WcfClient" EntityType="xxx.WcfClient"/>
<EntitySet Name="WcfService" EntityType="xxx.WcfService"/>
<AssociationSet Name="xxx_WcfClient_Application_xxx_SoaApplication_ApplicationPartnerSet" Association="xxx.xxx_WcfClient_Application_xxx_SoaApplication_ApplicationPartner">
<End Role="ApplicationPartner" EntitySet="WcfClient"/>
<End Role="Application" EntitySet="SoaApplication"/>
</AssociationSet>
<AssociationSet Name="xxx_WcfService_Application_xxx_SoaApplication_ApplicationPartnerSet" Association="xxx.xxx_WcfService_Application_xxx_SoaApplication_ApplicationPartner">
<End Role="ApplicationPartner" EntitySet="WcfService"/>
<End Role="Application" EntitySet="SoaApplication"/>
</AssociationSet>
<AssociationSet Name="xxx_WcfService_Clients_xxx_WcfClient_ClientsPartnerSet" Association="xxx.xxx_WcfService_Clients_xxx_WcfClient_ClientsPartner">
<End Role="ClientsPartner" EntitySet="WcfService"/>
<End Role="Clients" EntitySet="WcfClient"/>
</AssociationSet>
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
The WcfService
class has a property, List<WcfClient> Clients
, which I would like to populate with a list of clients associated with the WcfService
.
The WcfService
class looks kinda like this:
[DataServiceKey("ServiceId")]
public class WcfService
{
[Key]
public int ServiceId { get; set; }
... snip ...
public List<WcfClient> Clients { get; set; }
}
The code I have for add the relationship between the object looks like this:
var ctx = new Container(uri);
var service = ctx.WcfServices.Expand("Clients".Where(i => i.ServiceId == 21).ToArray()[0];
var client = ctx.WcfClients.Where(i => i.ClientId == 220).ToArray()[0];
ctx.AddLink(service, "Clients", client);
ctx.SaveChanges();
Unfortunately, an error occurs. This is the full request and response (edited for namespaces) that are sent across the wire (from fiddler)
Request:
POST http://soa.local.xxx/odata/WcfService(21)/$links/Clients HTTP/1.1
DataServiceVersion: 1.0;NetFx
MaxDataServiceVersion: 3.0;NetFx
Accept: application/atom+xml,application/xml
Accept-Charset: UTF-8
Content-Type: application/xml
User-Agent: Microsoft ADO.NET Data Services
Host: soa.local.xxx
Content-Length: 174
Expect: 100-continue
Connection: Keep-Alive
<?xml version="1.0" encoding="utf-8"?>
<uri xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">http://soa.local.xxx/odata/WcfClient(220)</uri>
Response:
HTTP/1.1 404 Not Found
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/7.5
DataServiceVersion: 3.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Sat, 15 Mar 2014 23:50:12 GMT
Content-Length: 565
<?xml version="1.0" encoding="utf-8"?>
<m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<m:code />
<m:message xml:lang="en-US">No HTTP resource was found that matches the request URI 'http://soa.local.xxx/odata/WcfService(21)/$links/Clients'.</m:message>
<m:innererror>
<m:message>No routing convention was found to select an action for the OData path with template '~/entityset/key/$links/navigation'.</m:message>
<m:type></m:type>
<m:stacktrace></m:stacktrace>
</m:innererror>
</m:error>
I don't understand why the format of the request url is '~/entityset(key)/$links/navigation'
and the error message says '~/entityset/key/$links/navigation'
?
It looks like the format used in the url was listed as supported in WCF Data Service 4.5. But, I'm probably looking in the wrong area for a solution.
Am I doing something wrong with the way I'm applying the change? Is there a more appropriate way to write the code?
Thanks
It looks like I needed to read the documentation more thoroughly. In Working with Entity Relations there are CreateLink
and DeleteLink
example methods. Once those methods were added to the Controller the calls started going through successfully.
I guess the routing convention is setup; but the error message occured because there were no methods to map the conventions to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With