Rants Tagged with “Data Services”

<<  <  1  2  3  >  >>  (Total Pages: 3/Total Results: 29)

Caveats About My Silverlight 2 Data Services Article

Silverlight Logo

As some of you may have seen, my new article in MSDN Magazine (and online) was recently published. Because we're in a bit of a no-mans-land with builds, the current article only works with .NET 3.5 SP1 Beta and Silverlight 2 Beta 2. This means if you're like most of the world and updated to the full release of .NET 3.5 SP1, some of the code in that article is not going to work for you. I hope to have a new drop of the code (and maybe the article too) once Silverlight 2 ships and is fully compatible with ADO.NET Data Services/Entity Framework that are in the full version of .NET 3.5 SP1.  See my other article talking about the incompatibilities here:

My apologies to anyone who spent too much time trying to get the code in the article working. Such is the problem with beta software and hopefully we'll have a solution sooner rather than later.

My ADO.NET Data Services/Silverlight 2 Article on MSDN Magazine

MSDN Magazine

My new article on creating Silverlight 2 applications that use ADO.NET Data Services is in the new issue of MSDN Magazine. In this article I show you how to create a ADO.NET Data Service as well as how to call that service using the Silverlight 2 Data Service Library. 

What is cool about this approach is that you can issue LINQ queries on the client (in Silverlight 2) that will communicate with Data Services via the REST interface and execute queries and update data on the server.  The substantial difference that you will have to get used to is the use of Asynchronous LINQ queries in Silverlight 2.  Check out the article for all the details.

VS 2008 SP1 RTM + Silverlight 2 Beta 2 == No ADO.NET Data Services

Silverlight Logo

UPDATE: This may be incorrect.  I am working with Microsoft to understand if I got this wrong.  I'll update this blog once I get the story right.

As everyone has announced already, Visual Studio 2008 and .NET 3.5 have released an SP1 that includes a bunch of fixes as well as the Entity Framework as well as ADO.NET Data Services. To support this, the Silverlight team dropped a new version of the Visual Studio tools that work with Silverlight 2 Beta 2 and Visual Studio 2008 SP1.

The one caveat is that the Silverlight library for ADO.NET Data Services is not compatible with the RTM of .NET 3.5 SP1's version of ADO.NET Data Services.  Since its not compatible, if you are using ADO.NET Data Services with Silverlight, you should wait to upgrade to Visual Studio/.NET SP1 until Silverlight 2 is released (there aren't any release dates for this yet). 

Note, that this is a little confused by the fact that SQL Server 2008 (released last week) requires Visual Studio 2008 SP1 RTM to install, so if you need both Silverlight 2 Beta 2 to work with ADO.NET Data Services and SQL Server 2008, there is no good solution for getting all three installed at once.

Implementing IUpdatable (Part 3)

Silverlight Logo

UPDATE: I know the title is wrong and it should be IUpdateable but I didn't want to break any links for any RSS feeds that already had it.

If you haven't read Part 1 or Part 2 first, you should start there.

In this final part of the IUpdateable implementation, we will discuss the rest of the methods which includes ClearChanges, ResolveResource, ReplaceResource, SetReference, AddReferenceToCollectionRemoveReferenceFromCollection and SaveChanges.

ClearChanges is a simple method that simple undo's any changes that have accumulated.  In my implementation, I simply clear the UpdateCache that we discussed in Part 2 as well as clear the NHibernate Session to undo any changed that were previously saved (but not persisted to the database).

ResolveResource is a funny little method. In the implementation documentation for the IUpdateable interface, they specify that in most cases you can return a token or anything you want that uniquely identifies an item instead of an actual object reference. For example, when you implement CreateResource the return value can be the actual resource or can be some token that you know how to resolve to the resource.  This method is the one that will turn that token into an object reference if you've used that functionality. In our case we're actually returning object references so this becomes a non-issue and we just return the object that is passed in.

Next up is ReplaceResource. Not surprising, this method is used to complete replace a resource with another copy (who may have the correct values already set). The first parameter is a query who must return a single object.  For my implementation, I first retrieve the single instance from the query and then walk through the properties to set the new values. Simple really.

The next couple of methods have to do with relationships between objects. The SetReference method takes three parameters: the target resource, the property name and the property value.  The property value is an object who needs to be assigned to a property of the target.  The property name to be assigned in the 2nd parameter.  The implementation is pretty simple: I used the existing SetValue implementation to set the correct property with the correct value.

The AddReferenceToCollection and RemoveReferenceFromCollection are related methods.  One adds an object to a collection and one removes it from the collection. Both of these methods take the same signature that SetReference uses (target, property name, property value). The difference here is instead of setting the reference, you need to add or remove it from a property (which is the collection). For my AddReferenceToCollection implementation, I use reflection to find an "Add" method and invoke it with the new reference. For the RemoveReferenceFromCollection, I do the same but I am looking for a "Remove" method to invoke. Using reflection in this way does not require that the collections follow any specific pattern but do require an Add and Remove method. I chose this implementation because I was copying ADO.NET Data Services' implementation that they use for the Entity Framework. I could have expected IList since that is the standard way that NHibernate usually implements collections, but I decided to use this implementation first and if I had to refactor it I would.

The last method to implement is SaveChanges. This method is pretty straightforward as all pending changes that the IUpdateable interface has applied should be applied during this call.  IUpdateable expects that SaveChanges will be atomic (e.g. pass/fail, no partial updates).  To enforce that requirement, I used the NHibernate Session object's BeginTransaction method to start a transaction so that I could rollback any changes that failed. Because I had kept a cache of updates so I could clear them if necessary, I walked through them once the transaction had began and applied them to the Session object.  Finally I flushed the session to force the persistence to happen and ended the transaction. I did this all in a try...catch block so I could rollback the changes if any exceptions were thrown. SaveChanges does not have a return value so if it fails you are expected to return a DataServiceException. So in my catch block, after rolling back the transaction, I throw a DataServiceException and pass along the caught exception as the inner exception.

Overall the implementation was pretty simple. I hope that these articles will help anyone who is trying to implement this for their own data that they want to use in ADO.NET Data Services.

 

Implementing IUpdatable (Part 2)

Silverlight Logo

If you haven't read Part 1 yet, you can read it here.

After spending time creating my own caches of reflection data I found the NHibernate type information to be more complete and faster. Go figure.  At this point I am using the SessionFactory's GetClassMetadata and GetCollectionMetadata to return IClassMetadata and ICollectionMetadata interfaces. So far this has given me every piece of runtime information I need and means that I don't need to do any nasty (and potentially fragile) walking through the property interface of the context object. Whew...

So to refactor my GetResource and CreateResource calls. GetResource is easy.  GetResource passes in the query and the full type name (though the full type name may be missing in some cases). The query it passes it must resolve to a single result.  That means I can simply execute the the query and if it returns more or less than one result, return an error.  Once I have the result I can just check it against the full type name (if it was passed in) and return the value.

CreateResource is a bit more complicated. The IClassMetadata allows me to call their Instantiate method to create a new instance of the class but the new instance is not initialized with any data.  Most notably, the missing detail is a key. In the case of many entities, this is fine (e.g. if zero ID is a valid "new" entity).  But in others the key needs to be specified. (Customer in the Northwind database is an example of this.) The problem is that we have to keep a reference to the new objects so that when ADO.NET Data Services asks us to set properties, get properties and save, we have to have the object in the Session.  But we can't add it to the Session with an invalid key.  What to do?  My solution for now is a local cache of objects that are not ready to be saved (only really happens with newly created objects). When we are ready to save, we'll just add it to the Session then (when its either valid or we'll throw an exception because its invalid).

Now a quick mention of GetProperty and SetProperty. These are both pretty easy as the IClassMetadata includes a similar method to set and get properties. The only wrinkle is that if you try and set a key using the GetProperty/SetProperty, the keys are not in the list of properties.  Because of this I just checked to see if the property is part of the key and set the key instead, if its not part of the key we can just set or get the property.  Now that we have the basic part of the interface complete  its down to the hard parts.   But that's for the next part!

 

Implementing IUpdatable (Part 1)

Silverlight Logo

I have been diving pretty deep into ADO.NET Data Services (see an upcoming article about ADO.NET Data Services and Silverlight 2 coming soon). I've been looking at the story around non-Entity Framework models through a Data Service and thought that NHibernate through a Data Service would be a great example.

So I tried to get it to work with the NHibernate LINQ project. The example model that the project uses is a simple Northwind model. I thought I'd just take that model and expose it via ADO.NET Data Services. I crufted up a simple Data Context object for ADO.NET Data Model but it didn't work. ADO.NET Data Services was complaining about the fact that the end-points (e.g. IQueryable<Customer>) was pointing at an Entity. This was a bug...a but in ADO.NET Data Services.  I hacked together a fix to get around it (and reporting it).  If you're interest, the problem is that if the key of the entity is in a base class and *not* named "ID", it fails to find it.  Again, this is a bug not a feature of ADO.NET Data Services.

Now that it was working, now what? I wanted to be able to make changes to the model but the NHibernate context doesn't support the updating interface: IUpdatable.  (Though I sure wish they'd rename it IUpdateProvider to match the IExpandProvider interface). If you're not familiar with this requirement, note that only the Entity Framework currently support the IUpdatable interface (and is in fact implemented inside of ADO.NET Data Services not directly in Entity Framework).  This means that DataSets and LINQ to SQL do not support it either. 

That's where I went to the Rhino Google Group (the discussion point for this project) and offered to implement the IUpdatable for the NHibernate provider. I thought it would be a fun exercise to understand the guts of the ADO.NET Data Service stack.

My first chore was to attempt to find a solution to decouple System.Data.Services.dll from the rest of the LINQ provider. My reasoning for this is that ADO.NET Data Services requires .NET 3.5 SP1 and I didn't want to tie the changes to that version of the Framework. Interestingly this is the same tactic that the ADO.NET Data Services team took.  This is why the Entity Framework does not implement the IUpdatable interface themselves, but the ADO.NET Data Service does it for them.  For the rest of the world, it expects a IUpdatable implementation directly on the context object that is used as the starting point for the service. After running around a number of ideas and running it by the Rhino people, we've decided to table that problem and get the interface working.  That will be a fight we fight later with a number of proposed solutions.

So now that architecture is out of the way, its time to start actually implementing the interface.  For the first pass, I am going to implement IUpdatable directly on NHibernateContext and refactor it later for less tight coupling. While I am at it, I also want to add support for IExpandProvider so that we can do expansions through NHibernate.

After adding the interface to the context object, I looked through the interface (its about a dozen calls that need to be implemented) to determine where to start. I am starting with the simple calls (GetResource, CreateResource, DeleteResource).  These calls are used by the service to do basic object manipulation.

For GetResource, I am handed a query and possibly a type name. GetResource is supposed to invoke the query to get the one and only one result (implementors should throw an error if the result returns more than one result) and then check the type name against the result.  In some cases you won't get the type name, but in most cases you will need to verify that the type of the result is the same as the type name. This is used to make sure that derived types are correctly retrieved from the data provider.

In implementing CreateResource, I noticed that I needed to be able to look up type information. Type information is important as I need information about the containers (e.g. IQueryable endpoints) on the context object.  This information is not readily available as its the classes that derive from NHibernate that add these end-points. I could get the type information via NHibernate's type information or using Reflection (neither are particularly cheap). For the first iteration I choose Reflection since I know that better, but I wanted to mitigate the cost with some caching. To that end, I've created some small in-memory caches of the reflection information that hopefully will help with the performance of these lookups.  This type information will help act like a factory to create new instances of the object. Unlike other ORM's, NHibernate doesn't use factories but uses simple object creation so we can just use the reflection information to create the instance of the new object and attach it to the NHibernate ISession.

Lastly, the simplest of the three methods to implement is the DeleteResource as it passes in a query (again, should always only return a single result) and mark it deleted in the session.  The change shouldn't be persisted (there is a SaveChanges call on the IQueryable interface that facilities the actual persistence to the data store).

Overall a fun couple of days.  Now on to the rest of the interface.  I'll keep you posted with my experience dealing with them!

Debugging ADO.NET Data Services...with Fiddler2

Silverlight Logo

When I deployed the small test application (http://www.silverlightdata.com/simple), it was pretty apparent that it was performing really badly. Some of this is because my ISP upload speed isn't great but it was still taking far too long I thought.  This was a simple app with not much data, so I knew I wanted to find out what was happening. If you haven't seen the site, its basically an editor for the Product table in the Northwind database.  Nothing special really.

ADO.NET Data Services does a lot of work for you under the covers.  This is good because we're not being asked to write a lot of serialization and transportation code, but it can be bad because it becomes more difficult to see why things are happening. Fiddler2 to the rescue!

If you're not familiar with Fiddler2, its basically a great tool for watching web traffic so you can see what is actually happening over the wire. For ADO.NET Data Services, we want to see the actual communication over the wire to see what was being sent to and from the Silverlight application.  First, grab the Fiddler2 tool (http://fiddler2.com/) and come with me!

So I fire up Fiddler2 and run the example page.  What do I see?  Nothing.  None of the traffic is showing up. A quick Google search reveals that Fiddler doesn't work on localhost or 127.0.0.1 (kinda the same thing). I found an odd workaround...add a period after the IP address.  So my "http://localhost:8000/Default.aspx" test page became "http://127.0.0.1.:8000/Default.aspx".  The period after the "1" is not a mistake.  Once I did that, the requests were showing up in Fiddler2.  Wahoo!

So what did I see? Here's a look at the Fiddler2 window (You can click it for a bigger view):

Looking at the request to Products.svc, I picked the "TextView" tab to see the actual body of the message.  Looking at it I noticed this Picture property that was base-64 encoded.  Uh oh...I didn't even notice that we are getting pictures...in fact we're getting duplicate data. My LINQ request was:

var qry = from p in TheContext.Products.Expand("Supplier")
                                       .Expand("Category")
          orderby p.ProductName
          select p;

I knew that I would be getting duplicate data by using the Expand extension method.  Expand says to embed the related entity (the Supplier and the Category) so that our object model doesn't have to lazy load them. Of course I wasn't paying attention.  The Category has a picture stored in the database. I am not even using it (and couldn't since the image is a GIF and Silverlight can't display GIFs) so retrieving it is pretty useless. Here's a quick view of the underlying Entity model:

The fix for me was to simply remove it from the model, but I am looking at different ways of really solving it including delving into how the "select" statement might filter these out, though I expect that doing three queries (one for Products then just returning Suppliers and Categories to remove the duplicate data would be much more efficient yet.

One caveat, this is the first release of the ADO.NET Data Services' Silverlight Client Library so give it time to improve some of the performance issues.  But like other data access libraries, sometimes small changes can make large improvements in performance.

Hope this helps you debug your own ADO.NET Data Services projects.

Using ADO.NET Data Services in Silverlight 2 Beta 2

ADO.NET Data Services

UPDATE: I had the PUT/POST reversed.  It reads correctly now.  (Thanks to commenter Rob for pointing it out).

Now that Silverlight 2 Beta 2 has launched, we have the ability to consume ADO.NET Data Services (formerly Astoria) from within Silverlight projects. ADO.NET Data Services are a perfect match for client-side technologies like Silverlight and ASP.NET AJAX.

For the uninitiated, ADO.NET Data Services is a new part of the .NET 3.5 framework that supports exposing a data model (e.g. LINQ for SQL, Entity Framework, etc.) as a set of queryable REST endpoints. ADO.NET Data Services maps the four data verbs into the four HTTP verbs:

  • Create == POST
  • Read == GET
  • Update == PUT
  • Delete == DELETE

Essentially it provides a way to use a data model across the firewall. It works by exposing IQueryable endpoints through a URI-based syntax allowing developers control over how the data is retrieved through:

  • Filtering
  • Sorting
  • Paging
  • Shaping

In addition ADO.NET Data Services utilizes JSON and Atom (though Plain Old XML may be supported eventually) as the serialization formats. These make it easy to consume in client-side interfaces like Silverlight and AJAX. For more information on ADO.NET Data Services, see there site:

http://msdn.microsoft.com/en-us/data/bb931106.aspx

Before you can consume a Data Service in Silverlight, you will need to create a model and service.  See Guy Burstein's walkthrough of creating the service here:

http://blogs.microsoft.co.il/blogs/bursteg/archive/2008/05/12/visual-studio-2008-sp1-ado-net-data-service-walkthrough.aspx

You *can* use LINQ to SQL as your data model but currently it does not have support for updating via ADO.NET Data Services so if you need to read and write data, you should start with an Entity Framework data model.

In Silverlight 2 Beta 2, ADO.NET Data Services is composed of an in-memory library allows asynchronous LINQ queries that are translated into the URI syntax automatically. Before you can get started you will need a a client-side version of the Data Context object and data contract classes for the entities in your data model. To do this, simply use the DataSvcUtil.exe tool located in the C:\Windows\Microsoft.NET\Framework\v3.5\ directory. Typically you would call it by specifying the URI of the service, the name of the class file to create and what language to use:

DataSvcUtil.exe /uri:http://localhost:8888/YourService.svc 
                /out:dataclass.cs 
                /language:CSharp

Once that class is created, add it to your Silverlight project.  You will also need to add a reference to the System.Data.Client.Services.dll assembly. Now we are ready to get some data. 

First we need to create an instance of the context class.  This class exposes each of the model types as queryable properties.  When creating an instance of the class, you must specify a URI to the service itself:

NorthwindEntities ctx = 
  new NorthwindEntities(new Uri("/Products.svc", UriKind.Relative));

Querying data with Data Services looks much like any other LINQ-based query:

var qry = from p in ctx.Products
          orderby p.ProductName
          select p;

Normally, you could execute the query directly by calling something like ToList() against the query.  Since that operation would cause a synchronous web request to happen across the network, that isn't supported in Silverlight 2 Beta 2.  In fact, if you try you will simply get a NotImplemented exception. In order to execute these queries, you will need to cast the query into a DataServiceQuery.  The DataServiceQuery allows you to call BeginExecute to start an asynchronous query as seen below:

// Cast the query to a DataServiceQuery
DataServiceQuery<Product> productQuery = 
                                  (DataServiceQuery<Product>)qry;

// Start the execution
productQuery.BeginExecute(new AsyncCallback(OnLoadComplete), 
                          productQuery);

Once the query completes, it will call the OnLoadComplete method that was specified in the AsyncCallback.  In this method, you first grab the DataServiceQuery that you sent with the request then end the execution to retrieve the results as seen below:

void OnLoadComplete(IAsyncResult result)
{
  // Get a reference to the Query
  DataServiceQuery<Product> productQuery = 
    (DataServiceQuery<Product>)result.AsyncState;

  // Get ther esults and add them to the collection
  List<Product> products = productQuery.EndExecute(result).ToList();
}

While its not as straightforward as synchronous execution, the new ADO.NET Data Services certainly works well in Silverlight 2 Beta 2 and provides a great way to use existing or planned data models over Internet applications. There are a couple of caveats:

  • Error handling and communication is very confusing right now as most real errors are being swallowed by the server instead of communicating back to the client. To find out what is really happening, use of Fiddler and enabling breaking on the throwing of all .NET exceptions will help a lot.
  • There are bugs on updating data that may get in your way.  Using Batch Saves will solve most of these issues.
  • Currently the Data Contract objects do not support INotifyPropertyChanged or INotifyCollectionChanged so data binding may be affected in some cases.There are partial methods for detecting changes to specific properties which makes implementing the INotifyPropertyChanged interface trivial, but not quick. Future versions (e.g. post-RTM) will give us better control over the generation of the data contract classes.
  • There is no built-in Visual Studio support to build the data contract/context classes.  This is also coming soon, though the exact schedule is unknown.

I am currently working on two examples for this (a simple one and a more complex one) as well as an article for MSDN, all of which will greatly expand the details of how to use ADO.NET Data Services (including how to save changes back to the server. Be sure to watch here for details of those samples and articles.

Upgrading Entity Framework and ADO.NET Data Services to SP1

Data

I've known Julie Lerman (or is it Julia these days ;) for a long time now.  She's an excellent resource for everything data related.  In particular she's been keeping up with the Entity Framework and ADO.NET Data Services (formerly Astoria) updates in .NET 3.5 and VS SP1 Beta that was just released this week.  If you are upgrading projects (like I am), she has two excellent blog posts about how to upgrade your projects:

New Entity Framework Changes

New ADO.NET Data Services (Astoria) Changes

Come Hear Me at the Alabama Code Camp this Saturday

Silverlight Logo

I will be at the Alabama Code Camp this weekend to talk about Silverlight, the Entity Framework and Astoria.  The talks I am doing are:

Feel free to stop by and harrass me with questions or disagreements.  I'll be there all day.