Published
Wednesday, December 19, 2007 9:30 AM
by
mtaulty
What flows backwards and forwards between a .NET "Data Services" client and its service? I've exposed Northwind.
Querying
Let's do a query from a .NET client (with generated code from the webdatagen tool);
NorthwindEntities en = new NorthwindEntities(
"http://mthpvista/DSTest/WebDataService.svc");
en.MergeOption = MergeOption.AppendOnly;
Customers c = (from x in en.Customers
where x.CustomerID == "ALFKI"
select x).First();
Console.ReadLine();
And here's the response - essentially, that LINQ query translates into a URI;
Customers('ALFKI')
and the response I get back is formatted for ATOM;
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xml:base="http://mthpvista/DSTest/WebDataService.svc/" xmlns:ads="http://schemas.microsoft.com/ado/2007/08/dataweb" xmlns:adsm="http://schemas.microsoft.com/ado/2007/08/dataweb/metadata" adsm:type="NorthwindModel.Customers" xmlns="http://www.w3.org/2005/Atom">
<id>http://mthpvista/DSTest/WebDataService.svc/Customers('ALFKI')</id>
<updated />
<title />
<author>
<name />
</author>
<link rel="edit" href="Customers('ALFKI')" title="Customers" />
<content type="application/xml">
<ads:CustomerID>ALFKI</ads:CustomerID>
<ads:CompanyName>cOMPANY5</ads:CompanyName>
<ads:ContactName>Maria Anders</ads:ContactName>
<ads:ContactTitle>Eggs</ads:ContactTitle>
<ads:Address>Obere Str. 57</ads:Address>
<ads:City>Berlin</ads:City>
<ads:Region ads:null="true" />
<ads:PostalCode>12209</ads:PostalCode>
<ads:Country>Spain</ads:Country>
<ads:Phone>030-0074321</ads:Phone>
<ads:Fax>Foo</ads:Fax>
</content>
<link rel="related" title="Orders" href="Customers('ALFKI')/Orders" type="application/atom+xml;type=feed" />
</entry>
Inserting
What happens when I do an insert? That is, run some code such as;
NorthwindEntities en = new NorthwindEntities(
"http://mthpvista/DSTest/WebDataService.svc");
en.MergeOption = MergeOption.AppendOnly;
Orders o = new Orders();
Customers c = new Customers()
{
CustomerID = "POST1",
CompanyName = "New Company"
};
en.AddObject("Orders", o);
en.AddObject("Customers", c);
o.Customers = c;
en.AddBinding(c, "Orders", o);
en.SaveChanges();
Big note - I'm not at all sure about that preceding code yet. I seem to have to both call the AddBinding() method and set the Order's Customer property - all feels a bit like "overkill" to me but (so far) that's what I have working.
First, we POST to /DSTest/WebDataService.svc/Orders
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xmlns:ads="http://schemas.microsoft.com/ado/2007/08/dataweb" xmlns:adsm="http://schemas.microsoft.com/ado/2007/08/dataweb/metadata" xmlns="http://www.w3.org/2005/Atom">
<content type="application/xml">
<ads:Freight ads:null="true" />
<ads:OrderDate ads:null="true" />
<ads:OrderID>0</ads:OrderID>
<ads:RequiredDate ads:null="true" />
<ads:ShipAddress ads:null="true" />
<ads:ShipCity ads:null="true" />
<ads:ShipCountry ads:null="true" />
<ads:ShipName ads:null="true" />
<ads:ShipPostalCode ads:null="true" />
<ads:ShipRegion ads:null="true" />
<ads:ShippedDate ads:null="true" />
</content>
</entry>
Then we get a response which contains;
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xml:base="http://mthpvista/DSTest/WebDataService.svc/" xmlns:ads="http://schemas.microsoft.com/ado/2007/08/dataweb" xmlns:adsm="http://schemas.microsoft.com/ado/2007/08/dataweb/metadata" adsm:type="NorthwindModel.Orders" xmlns="http://www.w3.org/2005/Atom">
<id>http://mthpvista/DSTest/WebDataService.svc/Orders(11165)</id>
<updated />
<title />
<author>
<name />
</author>
<link rel="edit" href="Orders(11165)" title="Orders" />
<content type="application/xml">
<ads:OrderID adsm:type="Int32">11165</ads:OrderID>
<ads:OrderDate adsm:type="Nullable`1[System.DateTime]" ads:null="true" />
<ads:RequiredDate adsm:type="Nullable`1[System.DateTime]" ads:null="true" />
<ads:ShippedDate adsm:type="Nullable`1[System.DateTime]" ads:null="true" />
<ads:Freight adsm:type="Nullable`1[System.Decimal]" ads:null="true" />
<ads:ShipName ads:null="true" />
<ads:ShipAddress ads:null="true" />
<ads:ShipCity ads:null="true" />
<ads:ShipRegion ads:null="true" />
<ads:ShipPostalCode ads:null="true" />
<ads:ShipCountry ads:null="true" />
</content>
<link rel="related" title="Customers" href="Orders(11165)/Customers" type="application/atom+xml;type=entry" />
<link rel="related" title="Employees" href="Orders(11165)/Employees" type="application/atom+xml;type=entry" />
<link rel="related" title="Order_Details" href="Orders(11165)/Order_Details" type="application/atom+xml;type=feed" />
<link rel="related" title="Shippers" href="Orders(11165)/Shippers" type="application/atom+xml;type=entry" />
</entry>
Then we POST to /DSTest/WebDataService.svc/Customers;
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xmlns:ads="http://schemas.microsoft.com/ado/2007/08/dataweb" xmlns:adsm="http://schemas.microsoft.com/ado/2007/08/dataweb/metadata" xmlns="http://www.w3.org/2005/Atom">
<content type="application/xml">
<ads:Address ads:null="true" />
<ads:City ads:null="true" />
<ads:CompanyName>New Company</ads:CompanyName>
<ads:ContactName ads:null="true" />
<ads:ContactTitle ads:null="true" />
<ads:Country ads:null="true" />
<ads:CustomerID>POST1</ads:CustomerID>
<ads:Fax ads:null="true" />
<ads:Phone ads:null="true" />
<ads:PostalCode ads:null="true" />
<ads:Region ads:null="true" />
</content>
</entry>
the response comes back;
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xml:base="http://mthpvista/DSTest/WebDataService.svc/" xmlns:ads="http://schemas.microsoft.com/ado/2007/08/dataweb" xmlns:adsm="http://schemas.microsoft.com/ado/2007/08/dataweb/metadata" adsm:type="NorthwindModel.Customers" xmlns="http://www.w3.org/2005/Atom">
<id>http://mthpvista/DSTest/WebDataService.svc/Customers('POST1')</id>
<updated />
<title />
<author>
<name />
</author>
<link rel="edit" href="Customers('POST1')" title="Customers" />
<content type="application/xml">
<ads:CustomerID>POST1</ads:CustomerID>
<ads:CompanyName>New Company</ads:CompanyName>
<ads:ContactName ads:null="true" />
<ads:ContactTitle ads:null="true" />
<ads:Address ads:null="true" />
<ads:City ads:null="true" />
<ads:Region ads:null="true" />
<ads:PostalCode ads:null="true" />
<ads:Country ads:null="true" />
<ads:Phone ads:null="true" />
<ads:Fax ads:null="true" />
</content>
<link rel="related" title="Orders" href="Customers('POST1')/Orders" type="application/atom+xml;type=feed" />
</entry>
Then we POST to /DSTest/WebDataService.svc/Customers('POST1')/Orders;
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xmlns:ads="http://schemas.microsoft.com/ado/2007/08/dataweb" xmlns="http://www.w3.org/2005/Atom">
<id>http://mthpvista/DSTest/WebDataService.svc/Orders(11165)</id>
</entry>
I'm not sure yet if that's exactly the right exchange pattern but in the RESTful world that's perhaps how you do things. I guess what's confusing me is the POST at the end - I'd kind of expect this to be a PUT but you're arguably creating a new relationship so perhaps that's why it's there like that.
Deleting
What about a delete? It seems to be as simple as sending a DELETE to the right URI. However, I have to admit that so far I can't manage to get code like this to work;
NorthwindEntities en = new NorthwindEntities(
"http://mthpvista/DSTest/WebDataService.svc");
en.MergeOption = MergeOption.AppendOnly;
var query = from c in en.Customers
where c.CustomerID == "POST1"
select c;
foreach (Customers c in query)
{
en.LoadProperty(c, "Orders");
foreach (Orders o in c.Orders)
{
en.DeleteObject(o);
}
en.DeleteObject(c);
}
en.SaveChanges();
I tried to first off use the $expand syntax to bring the orders back in one go but I find that no matter which syntax I use, I can't get a Customer and all their Orders to be deleted. I seem to be able to either delete the customer or the orders but not both in one go. I need to return to this! :-)
Updating
For a simple update what happens? Piece of code such as;
NorthwindEntities en = new NorthwindEntities(
"http://mthpvista/DSTest/WebDataService.svc");
en.MergeOption = MergeOption.AppendOnly;
var alfki = (from c in en.Customers
where c.CustomerID == "ALFKI"
select c).First();
alfki.Country = "France";
en.UpdateObject(alfki);
en.SaveChanges();
First off, I see the GET for the ALFKI customer and then the PUT for the new values (PUT /DSTest/WebDataService.svc/Customers('ALFKI'));
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry xmlns:ads="http://schemas.microsoft.com/ado/2007/08/dataweb" xmlns:adsm="http://schemas.microsoft.com/ado/2007/08/dataweb/metadata" xmlns="http://www.w3.org/2005/Atom">
<id>http://mthpvista/DSTest/WebDataService.svc/Customers('ALFKI')</id>
<content type="application/xml">
<ads:Address>Obere Str. 57</ads:Address>
<ads:City>Berlin</ads:City>
<ads:CompanyName>cOMPANY5</ads:CompanyName>
<ads:ContactName>Maria Anders</ads:ContactName>
<ads:ContactTitle>Eggs</ads:ContactTitle>
<ads:Country>France</ads:Country>
<ads:CustomerID>ALFKI</ads:CustomerID>
<ads:Fax>Foo</ads:Fax>
<ads:Phone>030-0074321</ads:Phone>
<ads:PostalCode>12209</ads:PostalCode>
<ads:Region ads:null="true" />
</content>
</entry>Note that this is only going to give you
current values so you'd be hard-pressed to do much in the way of "differencing" on the server-side in response to this.