Rants Tagged with “Data Services”

1  2  3  4  5  >  >>  (Total Pages: 5/Total Results: 42)

How We Used Data in GiveAQuiz.com

Silverlight Logo

As many of you may have heard, I recently launched http://GiveAQuiz.com as a new web site for creating and taking quizzes. The Data Team at Microsoft were great in helping me build this site. I've written a whitepaper detailing how we used the Microsoft data stack to accomplish it. This whitepaper shows how we used these data technologies to build the site:

If you are using Microsoft's Data stack for your own web-based and/or Silverlight site, give a look...hopefully some lessons learned you can use:

http://msdn.microsoft.com/en-us/library/ff847451.aspx

 

SQL Azure's OData Support

OData

I've ported my XBoxGames Database (see this blog article for copies of the .mdf files) to SQL Azure and added OData support. You can find the feed here:

https://odata.sqlazurelabs.com/OData.svc/v0.1/w9hratewlg/XBoxGames

While this rocks. it did expose some of the lack of full OData support in SQL Azure but they're working on them immediately.  Michael Pizzo is working on this support and send this list of what is and isn't working currently:

Supported:

Requests of the form “http://odata.sqlazurelabs.com/OData.svc/v0.1/[SQLAzureServerName]/[SQLAzureDatabaseName]” are recognized and correctly routed

  • Supports PowerPivot, Astoria Client/ASR, LinqPad, etc.

Integration with Portal, ACS

  • Impersonation based on security token for authenticated access
  • Anonymous access mapped to a particular user (read-only reference data, browser access,…)
  • Configuration information is read from a configuration table, hosted in sql azure

Metadata is dynamically loaded (changes to SqlAzure schema are immediately available through OData endpoint)

  • Pluralization support for entityset naming
  • IDs based on PKs
  • Relationships identified based on FKs
  • Goal is to generate an equivalent model to what EntityDesigner generates by default when doing modelgen from a database

The following requests are supported:

  •  ServiceDocument (/)
  •  metadata (/$metadata)
  •  entityset (/entitysetname)
  •  identity operator (/entitysetname(id))
  •  property navigation (/entityset(id)/propertyname)
  •  count (/$count)
  • single segment relationship navigation (/entityset(id)/navigationpropertyname)

The following query operators are supported:

  • $top
  • $skip
  • $orderby
  • $filter with basic expression support
  • $inlinecount
  • $select
  • $skiptoken

ServerDriven paging is supported

  • first 50 records plus NextLink

The following are supported in expressions:

  • math operators (add, subtract, multiply, divide, mod)
  • comparison expressions (equal, notequal, greaterthan, greaterthanorequal, lessthan, lessthanorequal)
  • logic expressions (AND, OR, NOT)
  • A host of string functions (length, substring, left, right, trim, replace, remove, upper, lower, startswith, endswith, concat, indexof)

Basic updating support

  • user-defined key values
  • autoincrement key values

Not supported (yet):
Stored procs
Tables/views w/no primary key
Date and Math scalar functions
EntityClient support
$expand
Many:Many relationships
Multi-level relationship navigation
Media Link Entries
Other feature requests?

Other Bugs:

Not listed in Michael's notes are a couple of other issues i've run into (but i've reported them to him so I expect they're going to be addressed soon):

Filtering along relationships:

  •  https://odata.sqlazurelabs.com/OData.svc/v0.1/w9hratewlg/XBoxGames/Games?$filter=Genre_1/Name eq 'Shooter'

Date Filtering:

  •  https://odata.sqlazurelabs.com/OData.svc/v0.1/w9hratewlg/XBoxGames/Games?$filter=ReleaseDate gt datetime'2009-12-12T12:00'

Ordering by Dates:

  •  https://odata.sqlazurelabs.com/OData.svc/v0.1/w9hratewlg/XBoxGames/Games?$orderby=ReleaseDate

 

WCF Data Services and jQuery

ODataI'd recently been asked by Chris Sells to help him with a simple WCF Data Services/jQuery example so I thought I'd share it via my blog as well. The basic idea is to use jQuery's AJAX functionality to retrieve JSON instead of the usual OData and consume it on a web page.

The example I decided on using is to expose the XBox database with paging. I am not doing any of the niceties like getting result counts to show a real navigation bar.  Instead this is quick and dirty to simply do "next" and "prev" and use WCF Data Service's URI API to retrieve data.

Like most of my XBox examples, I am using the Entity Framework to simply expose three entities types (Games, Genres and Ratings). Then I utilize a WCF Data Service to expose these types for consumption via REST.  My HTML is simple:

<h2>
  XBox Games</h2>
<div>
  <a href="#" id="PrevPage">Prev</a>
  <a href="#" id="NextPage">Next</a>
</div>
<div id="gameTable" />

The gameTable will simply be filled with a simple TABLE element for our data. So to the jQuery we go.  I am using plain jQuery 1.3.2 (though plugins could be used to simplify some of this code, I choose to just do it raw for simplicity).

First I set up a couple of variables to hold our paging information:

// globals for paging
var page = 0;
var pagesize = 25;

Next I handle the document's ready function to do some work when the initial page load is complete:

// Loads once the document has completed loading
$(document).ready(function () {
  
  // Set up paging buttons
  $('#PrevPage').click(function (evt) {
    // Stop the navigation from happening
    evt.preventDefault();
    if (page > 0) {
      page--;
      loadData();
    }
  });
  $('#NextPage').click(function (evt) {
    evt.preventDefault();
    page++;
    loadData();
  });
  
  // Load the initial data
  loadData();
});

When setting up the paging buttins, I use the '#PrevPage' and '#NextPage' CSS selectors to find items named PrevPage and NextPage and wire up the event to cause the page changes to happen.  The 'evt.preventDefault()' call stops the buttons from trying to navigate since we're using them as buttons.  FInally once we change the current page value, we call loadData (or in the initial case, call loadData with the default values).

function loadData() {
  var url = "/GameService.svc/Games?$orderby=Name" +
             "&$skip=" + (page * pagesize) + 
             "&$top=" + pagesize;
  $.ajax({
    type: "GET",
    url: url,
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function (msg) {
      loadTable(msg.d);
    }
  });
}

In the loadData function, I first create the URL by using the Data Service/OData URL API to retrieve games by Name while using the global values to retrieve a page of data at a time (see the $skip and $top parameters). Once the URL is defined, jQuery's ajax function executes the URL and returns in the success function in which we call loadTable to create the table for us. Since the returned JSON is contained in a 'd' element for security, we de-reference the 'd' element before we sent it into the loadTable function.

function loadTable(results) {
  var table = '<table><thead><tr><th>Name</th>' + 
              '<th>Publisher</th><th>Box</th></thead><tbody>';

  for (var post in results) {
    var row = '<tr>';

    row += '<td>' + results[post].Name + '</td>';
    row += '<td>' + results[post].Publisher + '</a></td>';
    row += '<td><img src="' + results[post].ImageUrl + 
           '" style="width: 100px; height=150px" /></td>';

    row += '</tr>';

    table += row;
  }

  table += '</tbody></table>';

  $('#gameTable').html(table);

}

Finally in loadTable some simple HTML construction goes on to create a table with our results.  The for loop returns a iterator for each row in the collection which we can use to retrieve the individual item (see results[post].Name as an example). Once the table is built, it replaces the contents of the element named gameTable with the new table.

Because WCF Data Services will return JSON as well, you can use it to do AJAX work just as effectively as Silverlight can consume it for rich client work.  You can get the code here:

http://wildermuth.com/downloads/DataServiceJQuery.zip

 

The State of Data Access in Silverlight

SilverlightI've said much about my opinion of Silverlight data access. Currently this is Web Services, WCF Data Services and WCF RIA Services. Let's talk about Data Services and RIA Services and how they are related:

WCF Data Services

Data Services are a good story in Silverlight, but only as of version 2.0 of the protocol. For those users of version 1.0, using Data Services was painful as automatic tracking did not exist yet. Data Services can create not only the data contract classes, but a context object that will do tracking and batching for you.  The basic story of how Data Services works is that it takes a context object from a LINQ provider and exposes all the IQueryable endpoints as REST resources that can be queried. This works well in creating a place to execute queries and post/put/delete changes. While Data Services' URI API is another skill that could be learned, the Silverlight (and .NET) client library allows you to just issue LINQ queries to the data service.  In addition, the ability to create client-designed graphs (e.g. embed relationships for eager loading) and navigate relationships to the server presents a good API for a data-centric application today.

The method for connecting to a data service is via a "Add Service Reference..." which means that it is easy to have data services projects that are outside a particular solution file. This is critical for when you are building very large projects.

One of my favorite things about Data Services today is the ability to create tracked projections from the Silverlight client:

var qry = from g in ctx.Games
          where g.ReleaseDate <= cutoffDate
          orderby g.ReleaseDate
          select new 
         {
           Name = g.Name,
           Id = g.Id,
           ReleaseDate = g.ReleaseDate
         };

This projection (which minimizes the data being sent over the wire from a Games entity), can be tracked like any other entity. This is a big boon for Silverlight clients where we want to reduce the surface area of the data being sent over the wire.

WCF Data Services' standard wire protocol is OData (which is a variant of ATOM). This means that tools like PivotTable, code-name Dallas and others can co-mingle data with other systems that are supporting OData like SharePoint, WebSphere, OpenGovernment project and SQL Azure table storage.

Some of the problems with Data Services include the fact that Service Operations are not part of the Silverlight proxy (and are not completely supported by the client library); any validation attributes of model information (like string length) are left on the client; and having to wrap your collections as DataServiceCollections to support tracking.

While I think Data Services still represents a major case for Silverlight usage, it still has a way to go before I am completely satisfied.

WCF RIA Services

WCF RIA Services takes a different approach to data access the resembles a mix of Data Services and Web Services. In RIA Services a server project is set up to expose data across the wire, but instead of Data Services' approach of exposing queryable end-points, it creates methods on the server which can be executed to retrieve, update, insert and delete data. These methods can be crafted to take specific parameters which takes some of the responsibility for what to query out of the hands of the developer (which may be fine in some cases). RIA Services does take model constraints and validation attributes and generate them in the client, which is a big win.  Also, RIA Services is like Data Services in that you can still do basic sorting, filtering and paging via the service.

The way that RIA Services is wired up to a project (via a Shared Code folder that is generated as the server-side project changes) is sexy, but for large projects the need to keep the RIA Services' project in the same solution (or use a project file hack to get it working) becomes an issue.

RIA Services is really built for the RIA Services' DomainContext to be the center of the application (which you can see when you look at demos utilizing their Data Source object that automatically wires up data as XAML elements). While you can write a loosely coupled application, it takes planning and is not the natural design of the API.

Other issue I have is with the design of the Load API where the attempt is made to hide the asynchronicity of the call.  The problem is that when errors happen on the load operation, it is hard to capture the error (other than letting it be cause as a top-level exception) so that most users will need to provide a callback which is just like having a full asynchronous operation. No better than before but the principle of least surprise isn't followed.

Finally, in comparison with Data Services, RIA Services has a lot of the same features but is missing the ability to do projections, client-defined eager loading and loading properties (e.g. relationships).

What does all this mean?

 So here we sit as Silverlight developers and we are being asked by Microsoft to choose of the three major options for data access. The problem is that none of them are perfect by any stretch of the imagination. I would think that Data Services and RIA Services are both great solutions but they are both missing features the others have.  In some ways the generation of these two projects has caused a lot of confusion as to which is the prescribed method for doing data access in Silverlight. It reminds me of the Entity Framework vs. LINQ to SQL debacle.

But where do we go from here?  I'd like to implore Microsoft to fast-track the work needed to provide parity in these products. That means build the underpinnings of both projects from the same underlying platform. That way the features of each platform could be included in the other. The features do not become the discrimator but instead it is the style of data access.  We want and need the missing features on both platforms:

  • "Add Service Reference..." Linkage to support large development projects.
  • Exposure and code-generation of any EDMX constraints and Validation attributes.
  • Projection and tracked minimizing projection support.
  • Full eager loading and navigation support.
  • Operations and Endpoints have the same level of support in the generated code.
  • Obvious and simple communication APIs to prevent the library from surprising us with error propagation.

...One More Thing

I also have the request that for the next development cycle that we provide secondary methods for communicating validation information than just validation attributes.  Validation attributes cause our server-side POCO classes to be not really POCO (since they have to have a reference to the validation assembly).  As well as most cases require us to use the painful and hacky MetadataClass method of creating a class to *only* hold these attributes. You don't have to get rid of the attributes, just let us feed them to the model in other ways (open the hooks, we'll decide how to communicate it; whether it be a DSL, XML file, database, etc.).

Your Job

As a reader of this blog, I'd like to ask you a favor.  Respond to this blog entry. I want to make sure my frustration with the two data access stacks is not just my annoyance but is causing confusion and pain to you my readers. If you agree, just comment (it can be just saying "I agree") so I can make sure the Data team at Microsoft understands how it impacts Silverlight (and others) development efforts.  Thanks!

 

Choosing a Data Access Layer for Silverlight 3

SilverlightIf you're a regular reader of my blog, you'll probably remember my pithy blog post where I stated that "It all depends..." to the question "Which Data Access Should I Use for Silverlight 3?"  The reality is that much like the similar question I am confronted with at user groups for the past decade ("What data access should I use in my .NET app?"). The reasons for picking a strategy are wide and varied so I will not try to analyze all possible outcomes, but I think the different strategies need to be explained better.

The three major candidates in Silverlight 3 are Web Services (WCF/ASMX), ADO.NET Data Services and RIA Services.  In any situation, any of these will work. But they are suited to different styles and requirements. Here's the abridged differences between the stacks:

  • Web Services: Interface-based Data Access
  • ADO.NET Data Services: LINQ-based Data Access with change management
  • RIA Services: Interface-based Data Access with change management

Let's dive deeper into explaining these differences and why that might matter.

Web Services

Using web services is the tried and true method for communicating across the firewall. This pattern is well known and reliable. In general this requires you specify an interface for the CRUD operations as separate operations on a web service then dutifully call them in your Silverlight code.

Reasons to Use: Any existing investment in web services can be a great reason to use them (whether in code or skillset). Also, web services are often used in cases where a project wants a very close control over the flow from the application to the database.

Reasons to Avoid: With web services you end up having to keep track of the changes yourself and know what services to call with updates. Any need for batching or transactional support gets cumbersome and code-intensive.

ADO.NET Data Services

ADO.NET Data Services is a simple REST-based facility for data access. It relies on the HTTP stack to help define the interface. GET calls become Reads, POST becomes Updates and so on. It uses ATOM or JSON for its serialization format so it is consumable by a variety of clients.

Underneath its covers it takes this URI based API and converts it into a LINQ call for GETs and to API calls to the provider for inserts, updates and deletes. That means that ADO.NET is a thin layer who's purpose is to translate the URI model to data access code.  But its better than that...

The real power of ADO.NET Data Services for Silverlight is the inclusion of the Client Library. This client library allows you to issue LINQ queries defined in the client and executed on the server. While the LINQ syntax is somewhat limited when compared to the server, it fulfills the 80% case and ADO.NET Data Services allows you to add operations to fill in the rest when necessary. In addition, the client library includes a powerful data context class that can monitor changes and issue changes in batches with transactional support.

Exposing your data access with ADO.NET Data Services is about exposing queryable end-points instead of defining an interface. This is what makes is unique. For example, we can query our service using a LINQ Query like so:

// Silverlight Code

// Create the query using LINQ
var qry = (from g in ds.Games
           where g.Price < 50m
           orderby g.Name
           select g) as DataServiceQuery<Game>;

// Execute the Query
// (This part is getting cleaner in ADO.NET Data Services v1.5) 
qry.BeginExecute(new AsyncCallback(r =>
  {
    games2.ItemsSource = qry.EndExecute(r).ToList();
    games2.DisplayMemberPath = "Name";
  }), null);

Reasons to Use: Want a simple, secure model where the developers can define the queries they need in code instead of changing the interface as the needs change.  The ADO.NET Data Services' client library makes the amount of code you write on the client small as it becomes LINQ calls and working with the context class.

Reasons to Avoid: When you want tight control over the interface to your data access and do not want developers issuing LINQ queries directly from the client code.

RIA Services

As the new kid on the block, RIA Services has a lot to offer. RIA Services is based on the idea of creating a data access API on the server and at the same time creating the client code in Silverlight (and other platforms in the future). Its focused on sharing code between the client and the server including validation logic.  In addition, while it allows you to create a set interface, it also provides a context object which can monitor changes on the client and batch those changes back to the server. In some ways RIA Services is like a hybrid of Web Services and ADO.NET Data Services.

Because RIA Services is based on a server-side query defined in its interface, on the client we call the query by calling the call on the interface:

// Silverlight Code

// The context object that tracks changes
XBoxGamesContext ctx = new XBoxGamesContext();

// Our RIA Query, really a call to an interface
var qry = ctx.GetGamesByGenreQuery("Shooter");

// Bind the data
theList.ItemsSource = ctx.Load<Game>(qry).AllEntities;

While in ADO.NET Data Services you are issuing LINQ queries, RIA Services also allow you to add LINQ constraints to the query endpoints.  For example instead of just creating a query by calling the interface, you can add LINQ expressions to the endpoint like so:

var riaQry = ctx.GetGamesQuery()
                .Where(g => g.Price < 50m)
                .OrderBy(g => g.Name);

LoadOperation<Game> op = 
  ctx.Load<Game>(riaQry);

Reasons to Use: RIA Services is a good choice if you expect to develop a straightforward application minimum number of tiers. It works best in Rapid Application development scenarios versus large architected applications. RIA Services does support a mix between the interface based from Web Servics and and LINQ based querying that is supported by ADO.NET Data Services.

Reasons to Avoid: RIA Services leverages a lot of magic code generation to make it work and that is harder to debug than it should be. Integration with large enterprises is possible, its not as easy it as it should be.

"So Which Would You Suggest?"

While I paint this picture of data access in Silverlight with a broad brush, I still get the question to suggest one over the other. The fact remains that there isn't a right/wrong answer here. A lot of it depends on the environment, project and skillset of the developers. So, no...I won't tell you what I suggest because I don't know the requirements and environment you work in. That's why they pay you the big bucks to be a developer, right?

How Silverlight 3 Validation Works

SilverlightAs RIA Services is plodding towards a release, many people are looking at it to help them with validation of data in Silverlight. Using this validation in Silverlight 3 is pretty straightforward but there are some caveats.  I want to show you under the covers so you understand what is happening. In this first part of the series, let's look at what it means to use validation from the outside.

How It Works

Back when Dynamic Data was being developed, a set of attributes was created to help tell the Dynamic Data folks about validation and other metadata so they could create smart scaffolds. These include:

  • RequiredAttribute
  • StringLengthAttribute
  • RangeAttribute
  • RegularExpressionAttribute

In addition, there were attributes that could tell Dynamic Data about how to name fields and such. This meant that if you were using a POCO class or a DTO, that you could do the annotation like so:

public class GameInfo
{
  [Required]
  [StringLength(100)]
  public string Name { get; set; }

  [Range(0d, 1000d)]
  public decimal Price { get; set; }
}

When the GameInfo class is generated on the client, that's how the validaiton is happening.  On the client we can simply bind to the DataForm to show the validation in action:

RIA Validation

While the DataForm will do this in a generic fashion (or even let you define templates), many Silverlight applications would like this validation behavior without using the DataForm. In fact, all the Silverlight 3 controls now support it but only if you know how to bind the elements correctly. If we bind the GameInfo to a StackPanel with some controls, we can get this same validation experience:

RIA Validation without DataForm

This works in two ways.  First the controls themselves have support built-in for the validation part of the user control.  When you skin a TextBox or other control, part of the ControlTemplate is the validation UI. So you can change what that looks like. The controls themselves react to the validation errors because of the way they are bound. For example, this simple UI looks like this in XAML:

<TextBlock>Name</TextBlock>
<TextBox Text="{Binding Name, Mode=TwoWay, 
                              NotifyOnValidationError=true, 
                              ValidatesOnExceptions=true}" />
<TextBlock>Price</TextBlock>
<TextBox Text="{Binding Price, Mode=TwoWay, 
                               NotifyOnValidationError=true, 
                               ValidatesOnExceptions=true}" />

These three parts of the binding are critical to making this work. The validation is performed when the data is pushed back into the backing data but how does this actually work? The hint is in the "ValidatesOnExceptions".

With a TwoWay binding, when you lose focus on a control, the value is pushed back to the control (including going through any converters you have specified). Normally if an exception is thrown during that process it fails to update the underlying object, but just swallows that error. But if you enable it with these two binding markup extensions, it assumes that any exception thrown during the TwoWay operation is a Validation error. Back in Silverlight 2, you could do this by simply adding validation logic directly in your data classes like so:

public string Name
{
  get
  {
    return this._name;
  }
  set
  {
    if ((this._name != value))
    {
      if (value.Length > 100)
      {
        throw new ValidationException(
          "String cannot be longer than 100 characters");
      }

      this._name = value;
    }
  }
}

This is where the Validaiton attributes we mentioned earlier come in. The controls themselves do not make the check for the validation. Instead there are two classes that come into picture. ValidationContext and Validator. These classes can be used to test a property's or an entire object's set of validation attributes. Essentially, the ValidationContext sets up what needs to be validated and the Validator performs the validation like so:

public string Name
{
  get
  {
    return this._name;
  }
  set
  {
    if ((this._name != value))
    {
      var ctx = new ValidationContext(this, null, null);
      ctx.MemberName = "Name";

      // If fails, throws an excption
      Validator.ValidateProperty(value, ctx);

      this._name = value;
    }
  }
}

These classes working together validates the value against whatever ValidationAttributes are on the "Name" property (e.g. Required, StringLength) and throws a ValidationException when it fails.  In fact, lets look look at the RIA Services class it generates in Silverlight:

[DataMember()]
[Required()]
[StringLength(100)]
public string Name
{
  get
  {
    return this._name;
  }
  set
  {
    if ((this._name != value))
    {
      this.ValidateProperty("Name", value);
      this.OnNameChanging(value);
      this.RaiseDataMemberChanging("Name");
      this._name = value;
      this.RaiseDataMemberChanged("Name");
      this.OnNameChanged();
    }
  }
}

In fact, the first thing that the generated class does is call a base class method called ValidateProperty which does the same thing as our previous example. Understanding how this really works is key to debugging odd scenarios (like a validation exception showing up for a conversion failure).

Trouble with the Code Generation

Most of us are not using POCO classes (yet) for our data containers, but are using ORM's to build our data layers for us. This was a problem for the Dynamic Data folks back a while and came up with the idea of Metadata Types. A metadata type is simply a way of specifying a candiate class. In fact RIA services does this for you (if you ask it nicely) but you can specify these yourself. The key is the MetadataType attribute which is useful to do in the partial class. For example for an Entity Framework type:

[MetadataType(typeof(Game.GameMetadata))]
public partial class Game
{
  internal sealed class GameMetadata
  {
    // Metadata classes are not meant to be instantiated.
    private GameMetadata()
    {
    }

    public string Description;

    public string Developer;

    public EntityState EntityState;

    public int GameID;

    public Genre TheGenre;

    public string ImageUrl;

    [Required]
    [StringLength(100)]
    public string Name;

    [Range(0d, 2000d)]
    public Nullable Price;

    public string Publisher;

    public Rating TheRating;

    public Nullable<DateTime> ReleaseDate;
  }
}

This class is a place that the validation or dynamic data runtimes can look for the attributes. Note, that this example uses a nested type but it could be a completely separate type as well.

NOTE: This works with RIA Services great. But its a hack. To pretend its anything but a hack is deluding yourself. My opinion is that this sort of information that is view specific should probably be loosely coupled instead of tightly in the form of attributes. If we did this on POCO classes, we'd be forced to have the validation attributes exist as a reference in every place we need them.

Just RIA Services?

There are many organizations out there that aren't using RIA Services for their data access (and i'll blog soon about why RIA Services is just a solution, not *the* solution data access). But if you are already using ADO.NET Data Services or Web Services, hooking into the validation logic is difficult. Adding the attributes is difficult in Silverlight since the generated code doesn't have any place to hook up the attributes (and MetadataType isn't supported in Silverlight). In addition, the attributes are only part of the problem as you'd need to build in the ability to do the validation on the set/gets (which is possible with ADO.NET Data Services but impossible with today's Web Service proxies). So today, this is most easily accomplished using RIA services.  But I don't believe that in the best interest of developers.

If you've followed this blog, you know that I love the idea of choice (e.g. my LINQ to Hibernate ADO.NET Data Example). So I want to be able to leverage the Validation logic no matter what what data access you're using. I have started a new project called Niagara that I hope will address some of these issues.  See my blog post about it here:

http://wildermuth.com/2009/09/28/Introducing_Project_Niagara

 

ADO.NET Data Services 1.5 Feature: Projections

SilverlightIf you've been following my blog, you should know that I am keeping a pretty close watch on ADO.NET Data Services. The team recently released a second CTP of the new version with some interesting features. This CTP has some pretty compelling additions, but I am going ot focus on one in particular.

I've been teaching and using ADO.NET Data Services for a long time and I like showing off exposing a LINQ-based provider (Entity Framework, NHibernate or others) to a Silverlight application. While ADO.NET Data Services does expose its API through a REST API, the magic for me is in its use in Silverlight. In case you haven't been following along, using the Silverlight client you can issue a LINQ query through the Silverlight client (though in fairness, the full power of LINQ is not supported in the client):

var qry = (from g in ctx.Games
           where g.Genre.Name == "Shooter"
           orderby g.ReleaseDate
           select g) as DataServiceQuery<Game>;

qry.BeginExecute(new AsyncCallback(r =>
{
  try
  {
    theList.ItemsSource = qry.EndExecute(r).ToList();
  }
  catch (Exception ex)
  {
    // NOOP
  }
}), null);

This is a powerful feature so that (unlike web services) developers can use a looser service definition to define their data stack. Let the developer who needs data be able to sort, filter and shape that data as necessary.

The last part of that phrase is "shape" on purpose. When I first teach this technology, I am often asked "what sort of shaping do you mean?" In ADO.NET Data Services 1.0, you could shape it by returning a hierarchy of data using the Expand method in the LINQ query. For example, we can return the game data with the Genre entity attached to every game like so:

var qry = (from g in ctx.Games
                        .Expand("Genre")
           where g.Genre.Name == "Shooter"
           orderby g.ReleaseDate
           select g) as DataServiceQuery<Game>;

qry.BeginExecute(new AsyncCallback(r =>
{
  try
  {
    theList.ItemsSource = qry.EndExecute(r).ToList();
  }
  catch (Exception ex)
  {
    // NOOP
  }
}), null);

But this level of shaping is powerful but limited in scope. This is where ADO.NET Data Services 1.5 comes up trumps. In this new CTP we can now do projections to retrieve specific data. For example:

var qry = (from g in ctx.Games
           where g.Genre.Name == "Shooter"
           orderby g.ReleaseDate
           select new
           {
             Name = g.Name,
             ReleaseDate = g.ReleaseDate.GetValueOrDefault(),
           }) as DataServiceQuery;

This query creates a new anonymous type that has the two values we want instead of returning the entire entity. In any other .NET project this would be fine, but for Silverlight we can't use the anonymous type for data binding (for security reasons). So like other anonymous type uses in Silverlight, you must project them into a known type.  A type like that is pretty easy to cruft up if you need:

var qry = (from g in ctx.Games
           where g.Genre.Name == "Shooter"
           orderby g.ReleaseDate
           select new GameInfo()
           {
             Name = g.Name,
             ReleaseDate = g.ReleaseDate.GetValueOrDefault()
           }) as DataServiceQuery<GameInfo>;

This is useful to no only limit the fields you return but also to shape the result.  For example we can use the projection to retrieve the name, release date and the genre's name (normally a related object) like so:

var qry = (from g in ctx.Games
           where g.Genre.Name == "Shooter"
           orderby g.ReleaseDate
           select new GameInfo()
           {
             Name = g.Name,
             ReleaseDate = g.ReleaseDate.GetValueOrDefault(),
             GenreName = g.Genre.Name
           }) as DataServiceQuery<GameInfo>;

This is all well and good, but what about saving these projections? For the most part you should treat complex projections (like the one above) as read-only. But if you retrieve entities that are purely subsets of existing entities, then ADO.NET Data Services will handle it.  Though currently this is crashing in Silverlight (it is a CTP after all). I will update this if I find a way around the saving bug in the near future and post the demo at that time.

But in general this is an awesome new addition to the library that I hope will close some of the use-cases that forced me to write Service Operations in the past.

What do you think?

Silverlight Data Examples Have Been Updated!

Silverlight LogoIf you've never had the chance to visit my sister site (http://www.silverlightdata.com), now's a good time. I've updated my examples there to include my MVVM, Prism and Declarative UI examples (to go with the skinning/switchable Astoria example).  Take a look if you're doing Silverlight data-based applications.

"Which Data Access Should I Use for Silverlight 3?"

Silverlight Logo

It all depends...

 

 

 

DevTeach Silverlight+MVVM=Easy Demo

Silverlight Logo

Fun first day here at DevTeach. I a talk showing creating a MVVM application from scratch (using ADO.NET Data Services 1.5 CTP). Kathleen Dollard had introduced the concept earlier that day, but we teach it a lot differently so it was fun to show off building a full MVVM application in the span of 75 minutes. 

The project we built in the talk is now available here at:

I the demo is a little big because I included the database (that includes some additional information). You will need Silverlight 3, ADO.NET Data Services 1.5 CTP and to attach the database (as XBoxStore) to SQL Server Express to get the demo to work. I introduced the topic of separation and isolation of contract with interfaces.  Hope it helps!