Mike Taulty's Blog
Bits and Bytes from Microsoft UK
ADO.NET Data Services - Experimenting with .NET Client Access Whilst Sniffing the HTTP Traffic.
Mike Taulty's Blog

Mike's Badges

Follow on Twitter
View mike's profile on slideshare
Add to Technorati Favorites
CW Blog Awards

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.
Posted Wed, Dec 19 2007 9:30 AM by mtaulty

Comments

Mike Taulty's Blog wrote ADO.NET Data Services - Using LINQ to SQL rather than LINQ to Entities
on Wed, Dec 19 2007 10:05 AM
Something that's been foxing me is that I've read about ADO.NET Data Services now supporting a &quot;provider&quot;...
ADO.NET Data Services - Experimenting with .NET Client Access … | ok wrote ADO.NET Data Services - Experimenting with .NET Client Access &#8230; | ok
on Wed, Dec 19 2007 10:28 AM
ADO.NET Data Services - Experimenting with .NET Client Access … | ok wrote ADO.NET Data Services - Experimenting with .NET Client Access &#8230; | ok
on Wed, Dec 19 2007 10:28 AM
Jason Haley wrote Interesting Finds: December 20, 2007
on Thu, Dec 20 2007 7:44 AM
Ode To Mike Taulty at Lost In Tangent wrote Ode To Mike Taulty at Lost In Tangent
on Thu, Dec 20 2007 10:15 AM
?????????????????? ???????????????????? ????????????, ???? ???????????????????????????? ????????… « ???????? ???????????? ?????????????? wrote ?????????????????? ???????????????????? ????????????, ???? ???????????????????????????? ????????&#8230; &laquo; ???????? ???????????? ??????????????
on Mon, Jan 14 2008 2:19 PM
(C) Mike Taulty, 2009. All rights reserved. The information in this weblog is provided "AS IS" with no warranties, and confers no rights. This weblog does not represent the thoughts, intentions, plans or strategies of my employer. It is solely my opinion. Inappropriate comments will be deleted at the authors discretion. All code samples are provided "AS IS" without warranty of any kind, either express or implied, including but not limited to the implied warranties of merchantability and/or fitness for a particular purpose.
Powered by Community Server (Non-Commercial Edition), by Telligent Systems