Monday, November 24, 2008

LINQ to SQL Featured in Visual Studio Magazine’s December 2008 Cover Story

Speed O/R Mapping with LINQ to SQL” by Roger Jennings for the December 2008 issue carries the following deck:

LINQ to SQL continues to be a top contender in the .NET object/relational mapping tool market despite Microsoft's promotion of the Entity Framework as one of the "Pillars of SQL Server 2008: Dynamic Development."

The article includes a table that compares LINQ to SQL and Entity Framework features and a “Visual Studio 2008 SP1 Add-Ins Remove LINQ to SQL Roadblocks” sidebar that describes Huageti Systems’ DBML/EDMX Tools utility for LINQ to SQL and Entity Framework and Damien Guard’s T4 template for customizing LINQ to SQL partial class code generation.

Following are recent OakLeaf blog posts that relate to the story:

And here are a two minor corrections to the story:

  • In the main text, “Hibernate and NHibernate” should be preceded by “Java and .NET purists” as Hibernate is a Java O/RM tool.
  • In Table 1’s feature “Model-first design” for LINQ to SQL, “Not available” should read “Create Database supported”.

Note: The latest version of Huagati’s DBML/EDMX Tools support incremental modifications to the database schema underlying a LINQ to SQL project.

The issue also contains two outstanding articles: What VB Devs Should Know About C# by Bill Wagner and What C# Devs Should Know About VB by Kathleen Dollard.

LINQ and Entity Framework Posts for 11/17/2008+

Note: This post is updated daily or more frequently, depending on the availability of new articles.

Updated 11/24/2008 8:00 AM PST
• Updated 11/21/2008 9:00 AM PST
• Updated 11/20/2008 5:30 PM PST

Entity Framework and Entity Data Model (EF/EDM)

• Ayende Rahien reports substantial increases in NHibernate downloads and posts to the NHibernate users group in his The NHibernate Community post of 11/22/2008.

Rick Anderson’s How to create an updateable view with ADO Entity Framework and with LINQ to SQL post of 10/03/2008 describes what the title claims. (Thanks to Steve Naughton for the heads up on Rick’s MSDN blog, which I wasn’t watching but am now.)

•• Frans Bouma takes the EF Team to task for their plans to force developers to write their own client-side update tracking code, not to mention rolling their own “wire-level format for changes sent from client to another tier,” in his Baby-sitter Framework 2.0: Change tracking in the EF v2, it's still your problem post of 11/21/2008.

•• Ayende Rahien agrees with Frans in his Stealing from your client post of 11/21/2008. Ayende says “This Is Broken, By Design.” I agree with Ayende and Frans.

Jeff Derstadt, Jaroslaw Kowalski, and Diego Vega posted N-Tier Improvements for Entity Framework [v2] on 11/19/2008, which proposes the following “goal” for future n-tier implementations:

Entity Framework won’t define its own unique representation for the set of changes represented in an N-Tier application. Instead, it will provide basic building block APIs that will facilitate the use of a wide range of representations.

My Entity Framework Team Abandons Unified N-Tier Architecture for v2 provides more details about the team’s decision to abandon a unified n-tier architecture for EF v2.

Milind Lele mentions that VS 2010 will support drag-and-drop data binding for WPF in his Drag-drop data binding for WPF in Visual Studio 2010 (Milind Lele) post of 11/19/2008 and notes:

In VS2010 we've added support for EDM in the data sources window. Thus when you add an EDM to your project, the entities show up in the [D]ata [S]ources window. You can simply drag the entities and drop them onto your WPF form or control to bind them.

His earlier Drag-Drop Data Binding For WPF post of 11/8/2008 has a screen capture of Northwind EntitySets in the Data Sources window.

John Papa offers Code from DevConnections 2008 in Las Vegas (11/18/2008) for the following sessions:

  • Implementing the Entity Framework
  • Data Access with Silverlight 2
  • Developing with Enterprise Library Data Access Application Block

Kim Major’s Entity Framework – Some common hurdles post of 11/17/2008 describes how his repository implementation deals with the following issues:

  • No eager loading. Need to specify .Include(“”) for every query.
  • No way to make to turn change tracking on/off except from changing every query.
  • A bug that prevents simple queries where nvarchar columns are used in the criteria.
  • A designer error with a cryptic error message.

His earlier Data Access With The Entity Framework (11/12/2008) and Testable Data Access With The Repository Pattern (11/14/2008) posts describe Renaissance Computer Systems Ltd.’s EF-based framework.

LINQ to SQL

••• Visual Studio Magazine’s “Speed O/R Mapping with LINQ to SQL” cover story by Roger Jennings for the December 2008 issue carries the following deck:

LINQ to SQL continues to be a top contender in the .NET object/relational mapping tool market despite Microsoft's promotion of the Entity Framework as one of the "Pillars of SQL Server 2008: Dynamic Development."

The article includes a table that compares LINQ to SQL and Entity Framework features and a “Visual Studio 2008 SP1 Add-Ins Remove LINQ to SQL Roadblocks” sidebar that describes Huageti Systems’ DBML/EDMX Tools utility for LINQ to SQL and Entity Framework and Damien Guard’s T4 template for customizing LINQ to SQL partial class code generation.

The LINQ to SQL Featured in Visual Studio Magazine’s December 2008 Cover Story post of 11/24/2008 adds related OakLeaf blog links and a couple of minor corrections to the text and table.

Rick Anderson’s How to create an updateable view with ADO Entity Framework and with LINQ to SQL post of 10/03/2008 describes what the title claims. (Copied from the “EF/EDM” topic.)

Kristofer Andersson’s Tools - Part 6 - Add-ins - “Model First” in Linq-to-SQL (and Entity Framework) post of 11/21/2008 describes a new feature of his Huagati DBML/EDMX Tools that enables generating the underlying database from a LINQ to SQL O/R Designer model and then incrementally updating the database schema with change scripts as the model matures.

Incremental updates are important because LINQ to SQL’s current model-first implementation [re]generates the entire database for each design update. The EF team’s stated intention for EF v2 is exactly the same. In both cases, the developer must recreate all data, relationships, indexes, etc. manually or author a hand-written change script. Regenerating the database for model changes is not acceptable in a production O/RM tool.

Kris’s post includes screen captures of an example that adds two tables related to Northwind’s Employees table. If you’re working with LINQ to SQL or EF, you need the Huagati DBML/EDMX Toolkit.

Deepak ? demonstrates how to Dynamic Sort With LINQ To SQL in this 11/19/2008 post. He writes a complex method with the Expression type, which he finally simplifies to a simple GetSortedEmployees<T> function with a lambda expression to specify the OrderBy predicate.

Matt Warren’s Building a LINQ IQueryable Provider - Part XII post of 11/17/2008, following a four-month hiatus, wraps the code from his previous 11 episodes into a single IQToolkit project that also includes testing code. Matt describes the changes from the earlier, incremental code base:

One of the first things you'll notice when you take a look at the source is that I changed it quite a bit.  I moved code around, changed names gratuitously, added & removed classes and broke a lot of continuity with the prior versions. One of the biggest changes is that the code is no longer just a sample.  All those internal classes are public, the project builds as a DLL, the tests are hosted separately and the namespace is no longer 'Sample.'

Bravo, Matt! A vituoso performance.

••• Matt posted his IQToolkit source code to CodePlex on 11/21/2008

Deepak ?’s  Enum Support With LINQ To SQL And SqlMetal post of 11/18/2008 describes his approach for using an enum in code. His “solution is to generate dbml file using SqlMetal, then run a custom process which modifies dbml to make it enum ready and finally generate code using SqlMetal looking over dbml file.”

LINQ to Objects, LINQ to XML, et al.

Bart De Smet’s Dude, Where’s My LINQ DML? post of 11/22/2008 discusses adding DML for “batch updates that don’t require client-side input or computation.” Bart demonstrates attempts at “Updateable LINQ to Objects,” “Updateable remotable LINQ,” and “Introducing IUpdateable<T>”, but bails with the following:

I’ll leave a concrete implementation of an update provider to the inspired reader; a basic prototype for SQL (only allowing columns to be updated with constant string or integer values) worked like a charm.

Bart: How about providing your “basic prototype for SQL” code?

Note: As reported last week, Rob Conery “added some spice to [SubSonic 3.0] and now we have a batch-updatable (read: one connection, one sql execution) Add/Update/Delete for the Repository which you can download here ([he]'ll include this in subsequent releases).”

Eric White demonstrates LINQ to XML generating an Inner Join of Two Excel Tables directly from the spreadsheet.Table(“TableName”) sources in this post of 11/20/2008.

LinqMaster’s Iterators, Lambda, and LINQ post of 11/20/2008 claims to be “The path to understanding Lambda and LINQ.” Sounds like LinqMaster is attempting to emulate Siddhartha Gautama in the LINQ department.

Aghy (Agnes Molnar) points to an updated version of LINQ4SP (LINQ to SharePoint) RC2 with its timebomb extended to 1/1/2009 in her Linq4SP - RC2 timebomb extended post of 11/20/2008. The earlier version expired a few days ago (in advance of the availability of paid licenses.)

Mike O’Brien’s Importing and Exporting Data Using Linq post of 11/18/2008 demonstrates how to export data from a SQL Server table to XML using LINQ to SQL and LINQ to XML.

ADO.NET Data Services (Astoria)

Marcelo Lopez Ruiz’s Limiting how many entities are returned from an ADO.NET Data Service post of 11/19/2008 explains that you can limit the number of entities on the server as well as with the $top query string option. Marcelo says:

MaxResultsPerCollection allows you to limit not only the number of entities returned at the top level of a request, but also at each collection within, so clients can't use '$expand' to overwhelm the server. Because a batch request can have multiple queries, you can combine that with MaxBatchCount.

However, use of these constraints is likely to throw exceptions.

He also cautions not to forget the dollar-sign prefix for system query parameters (options) in Filter not working in ADO.NET Data Services? of 11/18/2008

Brandon Bilinsky announced on 11/19/2008 that Like a Version; AtomPub Compliant for the Very First Time v2 of the Google Data APIs is fully compliant with the AtomPub standard (RFC 5032.) Like Astoria, Data APIs v2 uses HTTP ETags for optimistic concurrency management. Google’s Java and .NET client libraries have been updated with v2 support.

Rick Strahl’s ASP.NET Connection Session Slides and Samples Posted of 11/17/2008 describes and provides links to these sessions:

  • Using WCF for REST and JSON Services with ASP.NET
  • Using jQuery with ASP.NET
  • Dealing with Long Running Requests in ASP.NET

ASP.NET Dynamic Data (DD)

Rick Anderson solves a problem that occurs when you scaffold AdventureWorks’ CustomerAddress column in his Improving the FK field display: Showing two fields in Foreign Key columns with EF post of 11/21/2008. By default, DD turns the table’s first string column into a lookup field, in this case the Title field. Rick corrects the problem “by creating and annotating a partial class for the  Customer entity.”

Jonathan Carter’s Dynamic Data: The Little MetaModel That Could post of 11/20/2008 delve deeper into DD’s metadata classes: MetaTable and MetaColumn.

• Jonathan Carter posts the third episode as Dynamic Data: Models, MetaModels And Everything In Between on 11/19/2008. He notes that Dynamic Data provides …

A common meta-model system for describing data models with a higher semantic that a UI can leverage to be smarter by default. Out of the box, it includes providers for LINQ-To-SQL and the Entity Framework (which is why it has gotten a reputation for working solely against databases), but nothing stops it from working against any other data source. In fact, prototypes already exist that have Dynamic Data working against an ADO.NET Data Service, as well as a SQL Data Service.

Jonathan Carter follows up the first DD episode with Dynamic Data: Kickin’ It Old School of 11/19/2008, which provides a “contextual explanation as to why you might want to [leverage Dynamic Data within an existing web application], and what benefits may exist.

Jonathan Carter’s Dynamic Data: Come For The Scaffolding, Stay For Everything Else post of 11/17/2008 is the first episode of a new series about ADO.NET Dynamic Data. You might recall Jonathan’s earlier multipart series about ADO.NET Data Services.

Azure, SQL Data Services (SDS) and Cloud Computing

Roger Jennings uploaded the OakLeaf Systems Azure Table Services Test Harness to Windows Azure on 11/23/2008 and it’s now live at http://oakleaf.cloudapp.net/Default.aspx. For more details, see Windows Azure Test Harness Is Live! of the same date. A few features are disabled in the publicly available version.

Mike Amundson observes that SDS currently supports JSON (and ATOM) wire formats with Astoria functionality in his reply of 11/20/2008 to the JSON as alternative to XML for REST requests? thread in the SQL Data Services (SDS) - Getting Started forum.

The SDS Team’s Evan Basilik commented on the same date that “It does work, but is not an entirely "baked" part of the product.” Later posts request reassurance that, unlike Astoria, SDS will continue to support Plain Old XML (POX).

James Urquhart’s Do Your Cloud Applications Need To Be Elastic? post of 11/21/2008 quotes Citrix’s Cris Flex’s Cloud Economics 101 - Part 1 post of 9/27/2008 compares the cost of on-premises versus cloud computing on Amazon’s EC2. James concludes that cloud computing (with EC2) is only competitive with on-premises operations if you take full advantages of the ability to add and remove instances to satisfy periodic load peaks.

(Chris’s Cloud Economics 101 Part 2 - Premise Plus Cloud post of 10/13/2008 analyzes supplementing on-premises hosting with cloud computing for short-term demand spikes.)

Roger Jennings added the last three episodes to his Azure Storage Services Test Harness series:

  • Table Services 7 – Testing for Table Existence at App Startup Only (11/22/2008)
  • Table Services 6 – Paging LINQ to REST Query Result Sets (11/22/2008)
  • Table Services 5 – Generating Classes/Collection Initializers with LIMOG v2 (11/21/2008)

    • Pat Helland’s An Interview with .NET Rocks while I Was at Barcelona Last Week post of 11/20/2009 contains a link to an interview about the five sessions Pat presented at Tech*Ed EMEA 2008 Developer:

    1. When You Have Too Much Data, “Good Enough” is Good Enough
    2. Building on Quicksand
    3. RIAs and Emissaries
    4. Metropolis: Buildings and Applications
    5. Title Missing

    All have some relationship to cloud computing, but the interview emphasized topic #1.

    Roger Jennings added two new episodes to his Azure Storage Services Test Harness series:

    The goal is to wrap up the series by the end of this week.

    David Aiken’s illustrated Peeking [into] Windows Azure Queues using Windows PowerShell post of 9/12/2008 shows you how to use the CloudDrive Windows PowerShell provider from the Azure sample projects to browse and read queues.

    John Foley notes in his Next Headache: Cloud Chaos post of 11/19/2008 that:

    InformationWeek is preparing a report on how to get into cloud services, a hands-on guide to help you make a smooth transition, which we will publish in December. Those who want to ride the learning curve with peers should consider attending Cloud Connect, an "unconference" with a learn/develop/demo format. The event, co-sponsored by InformationWeek, takes place Jan. 20 to 22 at the Computer History Museum in Mountain View, Calif.

    So far, the “unconference” agenda has a severe case of the “Berkeley Vagues.”

    Steve Marx eliminates the performance hit caused by executing the CreateTablesFromModel() method against Azure Table Services on each server round trip in his Try to Create Tables Only Once post of 11/18/2008. I put his approach to work in the Global.asax.cs file added to my Azure Storage Services Test Harness.

    Oren Melzer’s The CardSpace “Geneva” Selection Experience post of 11/17/2008 explains the “newly designed selector in the new CardSpace ‘Geneva’ beta.” CardSpace is one of the authentication methods for the Azure Services Platform.

    Microsoft announced its Microsoft Business Productivity Online Standard Suite (MBPOSS) on 11/17/2008 and Mary Jo Foley analyzed its SharePoint capabilities in her What does ‘SharePoint in the cloud’ really mean? post of the same date. MBPOSS offers Exchange Online, SharePoint Online, Office Live Meeting, and Office Communications Online (later) “in the cloud” to potential users starting at $15.00 per month.

    Werner Vogels describes Amazon Web Services’ new edge-based content distribution network (CDN) for S3 called CloudFront in his Expanding the Cloud: Amazon CloudFront post of 11/17/2008. Nice name, by the way.

    SQL Server Compact (SSCE) 3.5 and Sync Services

    Steve Lasker’s Tech Ed EMEA 08 Powerpoints and Demos post of 11/19/2008 has links to slides and demo code from his two presentations:

    • DAT314  Unlocking the Power of SQL Server Compact 3.5
    • DAT405 Managing and Versioning Client Databases 

    Miscellaneous (WPF, WCF, MVC, Silverlight, etc.)

    Sam Gentile posted the 11th member of his SOA: Making the Paradigm Shift Part series on 11/23/2008 as Introduction to WCF: Architecture and the "ABCs" of Indigo." Sam says “The focus of this post is to show "Hello Indigo" code in a step-by-step manner. We will dive deep into the Indigo Architecture in the next installment of this series.”

    Rick Strahl attempts to divine the appropriate data transfer model to SQL Server parameterized stored procedures in his Silverlight and Data Communications post of 11/20/2008.

    David Betz’s Understanding WCF Services in Silverlight 2 of 11/16/2008 is a full-length tutorial for “access[ing] WCF services using Silverlight 2 without magic. There will be no proxies, no generated code, and no 3rd party utilities. Just raw WCF.”

    Rico Mariani’s The Visual Studio Tech Roadmap -- Starring Visual Studio 2010 post of 11/18/2008 presents Visual Studio’s chief architect’s view of the goals for VS 2010 and later, including a reference to future cloud-computing capabilities and tools (see the Danny Thorpe item below.)

    Simon Segal explains how he’s Moving on from Windows & Web Forms to Silverlight 2.0 in this detailed post of 11/18/2008.

    Scott Guthrie notes that Silverlight 3 will have “richer data-binding support” in his Update on Silverlight 2 - and a glimpse of Silverlight 3 post of 11/16/2008.

    Dare Obasanjo’s Live Framework (LiveFX), Is it Microsoft's GData or Something More? post of examines LiveFX and concludes:

    The client-side Live Operating Environment is a technology whose benefits elude me. I admit it is kind of cool but I can't see its utility.

    Danny Thorpe responds in his Client-Side Live Operating Environment: What’s It For? post of 11/18/2008 that “The answer, in a word, is ‘offline.’” Danny was a Principal Software Development Engineer for LiveFX who left Microsoft in October 2007 and returned in May 2008. He joined the Visual Studio incubation team that’s “working on stuff to make accessing Windows Live services easier for developers,” and is now Principal Engineer, Cloud Computing Tools.

    Kristofer Andersson’s Data Model - Basics - Part 11 - The HuagatiRes data model converted to “M” post of 11/15/2008 describes his conversion of the HuagatiRes airline passenger reservation system data model into an Oslo M script with a “code snippet that extracts schema, type, table, column, foreign key, and index defs and generates M files.” Kris says:

    Give it a connect string and an output folder and it will generate one M file per schema in the database you point it at, complete with code comments (based on object names and extended property descriptions) and all. Even [commented out] index definitions - prepared for the day when M gets support for index definitions.

    P.S.: Aker Brygge is the site of a former Norwegian shipyard (near Oslo) that’s been converted into a “shopping center with shops and restaurants, a cinema, office space, and apartments. Additionally, there is a small boat harbour, and a terminal for the ferries to Nesodden (across the Oslo fjord).”

    Kathleen Richards quotes me in her A Tale of Two 'Cities' article about Oslo and Dublin for Redmond Developer News’ November edition:

    Data-driven app developer Roger Jennings, a contributing editor to Redmond Developer News' sister publication Visual Studio Magazine and OakLeaf Systems blogger, says with Oslo Microsoft is moving toward a repository for componentized software. The company's intention is to make the visual designer Quadrant usable by business analysts -- to modify workflows, for example -- but whether that will work is unclear.

    "My feeling about Oslo is that they're trying to get business analysts involved in the design process, but not necessarily doing the design," says Jennings.

  • Saturday, November 22, 2008

    Azure Storage Services Test Harness: Table Services 7 – Testing for Table Existence at App Startup Only

    Update 1/31/2009: Code is now available for download.

    This is the first of a series of articles about a ASP.NET 3.5 C# test harness for Azure Storage Services that is will be available for download from my “Retire Your Data Center” cover story for Visual Studio Magazine’s February 2009 issue (click the Get Code Download link) in the near future.

    Most Azure Table Services sample projects invoke the TableStorage.CreateTablesFromModel() method before each attempt to perform CRUD operations in a user’s session. This method creates the named table if it doesn’t exist or sends a 409 “The table specified already exists” response message if it does. This is a relatively expensive process, especially if repeated before each CRUD request to the service.

    Steve Marx raised this issue in his Try to Create Tables Only Once post of 11/18/2008.

    This article describes the test harness’s code in the Application_BeginRequest event handler of the Global.asax.cs file to test for tables only at the start of the user’s session.

    Preceding episodes of this Azure Storage Services Test Harness series are:

    The HTTP POST Request and Response Headers for the CreateTablesFromModel() Method

    POST Request and HTTP Header (from Table Services 1 – Introduction and Overview):

    POST http://oakleaf.table.core.windows.net/Tables
    POST /Tables HTTP/1.1
    User-Agent: Microsoft ADO.NET Data Services
    x-ms-date: Mon, 10 Nov 2008 16:06:02 GMT
    Authorization: SharedKeyLite oakleaf:eRbDw5U7BkeSfZmKj71Zy3WTjrZCWkseVav3NK3tVqA=
    Accept: application/atom+xml,application/xml
    Accept-Charset: UTF-8
    DataServiceVersion: 1.0;NetFx
    MaxDataServiceVersion: 1.0;NetFx
    Content-Type: application/atom+xml
    Host: oakleaf.table.core.windows.net
    Content-Length: 499
    Expect: 100-continue
    Proxy-Connection: Keep-Alive
    
    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
        xmlns="http://www.w3.org/2005/Atom">
      <title />
      <updated>2008-11-10T16:06:02.1557288Z</updated>
      <author>
        <name />
      </author>
      <id />
      <content type="application/xml">
        <m:properties>
          <d:TableName>CustomerTable</d:TableName>
        </m:properties>
      </content>
    </entry>

    Notes: The maximum skew between the x-ms-date value and server UTC is 15 minutes. Blob Storage, Table Storage, and Queue support the SharedKey authentication scheme. The key signature is a Hash Message Authentication Code (HMAC) constructed from the request and computed with the SHA256 algorithm, then encoded using Base64 encoding. The ADO.NET Data Services’ .NET Client library (System.Data.Services.Client) supports a simpler SharedKeyLite authentication scheme only.

    POST Response Header and Message for Existing Table

    If the table doesn’t exist, the project creates an empty table. If the table exists, the POST attempt sends the following error response:

    HTTP/1.1 409 The table specified already exists.
    Cache-Control: no-cache
    Content-Length: 258
    Content-Type: application/xml
    Server: Table Service Version 1.0 Microsoft-HTTPAPI/2.0
    x-ms-request-id: 7b66eaa7-68f4-4926-ae43-579074b71c04
    Date: Mon, 10 Nov 2008 16:05:50 GMT
    
    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
      <code>TableAlreadyExists</code>
      <message xml:lang="en-US">The table specified already exists.</message>
    </error>

    Code to Execute TableStorage.CreateTablesFromModel() Once per User Session

    Ordinarily, you would expect to write code in the Global.asax.cs files’ Application_Start event handler for a once-per session initialization operation, but that doesn’t work for IIS 7. The test harness code code is based on Mike Volodarsky’s IIS7 Integrated mode: Request is not available in this context exception in Application_Start post of 11/10/2007, which notes that IIS 7 will throw an error if you attempt to execute code from Application_Start in IIS 7’s Integrated mode.

    ASP.NET Web Cloud Services don’t add a Global.asax.cs file by default, so you must add one to the ProjectName_WebRole project by selecting the Global Application Class in the Web category of the Add New Item dialog. The added Global.asax.cs file includes event-handling stubs for commonly used application-level events, including Application_BeginRequest.

    Here’s the test harness’s Application_BeginRequest code":

    Azure Storage Services Test Harness: Table Services 6 – Paging LINQ to REST Query Result Sets

    Update 1/31/2009: Code is now available for download.

    This is the sixth of a series of articles about a ASP.NET 3.5 C# test harness for Azure Storage Services that is will be available for download from my “Retire Your Data Center” cover story for Visual Studio Magazine’s February 2009 issue (click the Get Code Download link) in the near future.

    Azure Table Services HTTP Requests include a $top=n system query option that accepts NextPartitionKey and NewRowKey parameters to position the starting point of successive GET queries to the appropriate entity. HTTP Responses return the parameter values for the next retrieval. The feature implements a basic paging capability, where n is the number of entities returned. This article shows the C# 3.0 source code to implement paging of an ASP.NET GridView control’s contents.

    The article also shows sample code for performing iterative CRUD operations on the CustomerTable’s entities.

    Preceding episodes of this Azure Storage Services Test Harness series are:

    Request and Response Headers with Starting Position

    Following is a typical HTTP Request header that uses the table primary key value as the RowKey:

    GET /CustomerTable()?$top=7&NextPartitionKey=Customers&NextRowKey=BOLID HTTP/1.1
    User-Agent: Microsoft ADO.NET Data Services
    x-ms-date: Sat, 22 Nov 2008 18:29:56 GMT
    Authorization: SharedKeyLite oakleaf:t8J4j1oPPYuaPLzyjnFhJD0GZUATFhhwiTqdygkNysE=
    Accept: application/atom+xml,application/xml
    Accept-Charset: UTF-8
    DataServiceVersion: 1.0;NetFx
    MaxDataServiceVersion: 1.0;NetFx
    Host: oakleaf.table.core.windows.net

    Here’s the response header with the first and last CustomerTable entity of the page:

    HTTP/1.1 200 OK
    Cache-Control: no-cache
    Transfer-Encoding: chunked
    Content-Type: application/atom+xml;charset=utf-8
    Server: Table Service Version 1.0 Microsoft-HTTPAPI/2.0
    x-ms-request-id: 57cbcfb9-5e2f-407e-846d-69c06b7f12bc
    x-ms-continuation-NextPartitionKey: Customers
    x-ms-continuation-NextRowKey: COMMI
    Date: Sat, 22 Nov 2008 18:29:55 GMT
    
    24E1
    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <feed xml:base="http://oakleaf.table.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
      <title type="text">CustomerTable</title>
      <id>http://oakleaf.table.core.windows.net/CustomerTable</id>
      <updated>2008-11-22T18:29:55Z</updated>
      <link rel="self" title="CustomerTable" href="CustomerTable" />
      <entry m:etag="W/&quot;datetime'2008-11-12T23%3A08%3A46.0506837Z'&quot;">
        <id>http://oakleaf.table.core.windows.net/CustomerTable(PartitionKey='Customers',RowKey='BOLID')</id>
        <title type="text"></title>
        <updated>2008-11-22T18:29:55Z</updated>
        <author>
          <name />
        </author>
        <link rel="edit" title="CustomerTable" href="CustomerTable(PartitionKey='Customers',RowKey='BOLID')" />
        <category term="oakleaf.CustomerTable" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
        <content type="application/xml">
          <m:properties>
            <d:PartitionKey>Customers</d:PartitionKey>
            <d:RowKey>BOLID</d:RowKey>
            <d:Timestamp m:type="Edm.DateTime">2008-11-12T23:08:46.0506837Z</d:Timestamp>
            <d:Address>C/ Araquil, 67</d:Address>
            <d:City>Madrid</d:City>
            <d:CompanyName>Bólido Comidas preparadas</d:CompanyName>
            <d:ContactName>Martín Sommer</d:ContactName>
            <d:ContactTitle>Owner</d:ContactTitle>
            <d:Country>Spain</d:Country>
            <d:CustomerID>BOLID</d:CustomerID>
            <d:Fax>(91) 555 91 99</d:Fax>
            <d:Phone>(91) 555 22 82</d:Phone>
            <d:PostalCode>28023</d:PostalCode>
          </m:properties>
        </content>
      </entry>
    ...
      <entry m:etag="W/&quot;datetime'2008-11-12T23%3A08%3A46.8546837Z'&quot;">
        <id>http://oakleaf.table.core.windows.net/CustomerTable(PartitionKey='Customers',RowKey='CHOPS')</id>
        <title type="text"></title>
        <updated>2008-11-22T18:29:55Z</updated>
        <author>
          <name />
        </author>
        <link rel="edit" title="CustomerTable" href="CustomerTable(PartitionKey='Customers',RowKey='CHOPS')" />
        <category term="oakleaf.CustomerTable" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
        <content type="application/xml">
          <m:properties>
            <d:PartitionKey>Customers</d:PartitionKey>
            <d:RowKey>CHOPS</d:RowKey>
            <d:Timestamp m:type="Edm.DateTime">2008-11-12T23:08:46.8546837Z</d:Timestamp>
            <d:Address>Hauptstr. 29</d:Address>
            <d:City>Bern</d:City>
            <d:CompanyName>Chop-suey Chinese</d:CompanyName>
            <d:ContactName>Yang Wang</d:ContactName>
            <d:ContactTitle>Owner</d:ContactTitle>
            <d:Country>Switzerland</d:Country>
            <d:CustomerID>CHOPS</d:CustomerID>
            <d:Phone>0452-076545</d:Phone>
            <d:PostalCode>3012</d:PostalCode>
          </m:properties>
        </content>
      </entry>
    </feed>
    0

    The next CustomerTable entity in sequence is COMMI (Comércio Mineiro).

    Implementing Paging in Default.aspx.cs

    The following code in the Default.aspx.cs class file’s Page_Prerender event handler adds the starting NextPartitionKey and NextRowKey values to the query string parameters by invoking the AddQueryOption() method, executes the query. The code is based on Steve Marx’s Paging Over Data in Windows Azure Tables post of 11/12/2008.

    The code then extracts the successive NextPartitionKey and NextRowKey values for use in the query for the next page, as shown here:

    Here’s the page generated by the Development Fabric and populated from Cloud Storage (http:oakleaf.table.core.windows.net)  by the preceding code (click the image to display a full-size capture):

    Counting, Deleting, Creating, and Updating Table Data

    The Default.aspx.cs class file also contains event handlers for the Count Customers, Delete All Customers, Create Customers and Update Customers buttons, to perform iterative CRUD operations on the CustomerTable EntitySet. Creating Customer entities takes advantage of the classes and collection initializers generated by the LINQ In-Memory Object Generator (LIMOG) v2, which the Table Services 5 – Generating Classes/Collection Initializers with LIMOG v2 article describes.

    Here’s the code for the four event handlers:

    Friday, November 21, 2008

    Azure Storage Services Test Harness: Table Services 5 – Generating Classes/Collection Initializers with LIMOG v2

    Update 1/31/2009: Code is now available for download.

    This is the fifth of a series of articles about a ASP.NET 3.5 C# test harness for Azure Storage Services that is will be available for download from my “Retire Your Data Center” cover story for Visual Studio Magazine’s February 2009 issue (click the Get Code Download link) in the near future.

    A test harness is more useful to developers if it doesn’t depend on a sample relational database for its source of test data. This is especially true for a Windows Azure test harness because, unlike Amazon EC2 with a Windows Server 2003 VM, the Windows Azure operating system doesn’t include a relational database management system (RDBMS). Therefore, the test harness needs to mock data from relational tables in Azure’s Entity-Attribute-Value (EAV) format.

    This article describes a data-mocking application that provides the TableNameDataModel class and  in my Azure Storage Services Test Harness: Table Services 4 – Programming the Table Services API (11/20/2008) post.

    Updated 11/23/2008: See end of post.

    Preceding episodes of this series are:

    LINQ In-Memory Object Generator (LIMOG) v2

    The LINQ In-Memory Object Generator (LIMOG) v1 is a Windows Forms project that writes C# 3.0 or VB 9.0 code for classes that represent database tables and collection initializers to populate the classes. It’s described in Chapter 4, “Working with Advanced Query Operators and Expressions,” of my forthcoming Professional ADO.NET 3.5 with LINQ and the Entity Framework book from Wiley, which will be published in January or February 2009. Several of the book’s sample projects use code generated by LIMOG v1 to test LINQ to Object queries against simulated relational data.

    I updated the LIMOG v1 project to generate C# code (only) for similar classes with the added members (PartitionKey and RowKey) required to emulate Azure Tables Services entities and SQL Data Services entities (Id and Kind). Here’s the project’s UI for the Northwind sample database’s Orders table (click for full-size screen capture):

    You can select the database name or table name as the PartitionKey or SDS’s Kind value; database name places entities for all tables in the same partition, rather than using a separate partition for each table.

    You can select the table’s primary key value (the default) as the RowKey or SDS’s Id value; string values are used directly, numeric keys are converted to a 10-character, zero-padded string Alternatively, you can select increasing (auto-increment/identity) or decreasing 19-character zero-padded numeric string (to accommodate long/bigint values) or GUID values.

    After clicking Generate Code, clicking the two buttons at the bottom, right of the window copies the code to the clipboard for pasting to your VS 2008 project.

    Here’s the complete autogenerated OrdersDataModel class code:

    You can download from SkyDrive a pair of class and collection initializer text files with code for the eight original Northwind tables. (Image fields are omitted from these files, which are 7 kB and 870 kB in size.)

    Special-Case Fields in Collection Initializers

    To initialize a System.DateTime field from a supported DateTime format, use the DateTime.Parse(DateTimeString) method, as in:

    ..., ModifiedDate = DateTime.Parse("2004-06-01T00:00:00"), ... 

    To initialize a Guid structure from an input string, create a new Guid structure as in:

    ..., rowguid = new Guid("{e3a1994c-7a68-4ce8-96a3-77fdd3bbd730}"), ...

    Updated 11/23/2008: Autogenerated class code image and “Special-Case Fields in Collection Initializers” sections added; minor edits.

    Entity Framework Team Abandons Unified N-Tier Architecture for v2

    Updated 11/21/2008: See below

    Jeff Derstadt, Jaroslaw Kowalski, and Diego Vega posted on 11/19/2008 a lengthy N-Tier Improvements for Entity Framework [v2] article, which proposes the following “goal” for change management in future n-tier implementations:

    Entity Framework won’t define its own unique representation for the set of changes represented in an N-Tier application. Instead, it will provide basic building block APIs that will facilitate the use of a wide range of representations.

    The decision to abandon a unified n-tier architecture for EF v2 appears to stem from the anticipation that users would expect such a design to offer the programming simplicity of DataSets (represented by Martin Fowler’s Table Module pattern) combined with the versatility and strong decoupling offered by Data Transfer Objects. The availability of ADO.NET Data Services to provide a REST-based tiered service layer probably contributed to the designers’ justification of an n-tier non-goal.

    To achieve the proposed non-goal, the team intends to supply helper methods that developers can mix and match for customizing their tiered implementations to accommodate varying domain models, trust boundaries, batch operations, and optimistic concurrency management granularity. Following are the proposed methods, together with the authors’ summary of their purpose:

    • ApplyOriginalValues() applies property values to original state of the entity
    • ChangeObjectState() changes the state of the entity and incident relationships
    • ChangeRelationshipState() changes state (new, modified, or deleted) of a relationship
    • ChangeRelationshipState() (overload) changes state of a relationship represented by a navigation property
    • ChangeRelationshipState<TSource>() changes state of a relationship represented by a lambda expression

    The team presents simplified sample code for two scenarios:

    1. General purpose Attach with state resolution delegate in which the client sends a modified entity graph to the mid-tier for processing and persisting.
    2. ChangeOrder Service Operation in which the parent of a dependent entity is changed or added

    I’m disappointed by the authors’ compromised approach to n-tier EF implementation, but I’ll reserve judgment until I can test sample code for both simple and very complex, tightly controlled scenarios with POCO entities at least as convoluted as those from AdventureWorks. Hopefully, the sample code will include a complete test suite with mocked data.

    It will be interesting to hear the reaction to this approach from the ALT.NET petitioners, AKA the “NHibernate Mafia”, as well as that of the ADO.NET Advisory Council.

    Update 11/21/2008: Frans Bouma’s Baby-sitter Framework 2.0: Change tracking in the EF v2, it's still your problem post takes the EF team to task for forcing developers to write their own n-tier change-tracking code. Frans points out that clients or employers should not be required (or requested) to pay for writing data access code. Ayende Rahien agrees with Frans in his Stealing from your client post of the same date. Ayende says “This Is Broken, By Design.” I agree.

    Astoundingly, Jeff Derstadt said in a reply to Frans’ comment to the post:

    One of our goals was to avoid defining a part[i]cular wire-level format for changes sent from client to another tier.

    I’m no longer reserving judgment. This is Nuts! Not only must developers write their own client-side change-tracking code but kludge their own “wire-level format for changes sent from client to another tier.”

    Hopefully Matt Warren will revive his mini-connectionless DataContext for LINQ to SQL or Danny Simmons will productize Perseus.

    P.S. for Tim Mallalieu: We still haven’t seen the promised minutes of the Advisory Council’s first meeting.

    Microsoft Responds to LINQ to SQL Bug Report after Its First Anniversary

    On 10/15/2007, I posted LINQ to SQL's GetOriginalEntityState Doesn't Include EntitySet or Entity Ref Data for Related Entities as Feedback on the Microsoft Connect site. There’s more detail about the bug and even a test harness at my GetOriginalEntityState() Loses EntitySet/EntityRef Data of 10/15/2007.

    Lo and behold! On 11/21/2008 my morning’s e-mail contained the following:

    Greetings from Microsoft Connect!

    This notification was generated for the following Feedback item: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=304732 which you submitted at the Microsoft Connect site (http://connect.microsoft.com).

    Hello Roger,

    As Matt explains this is by design. Informatoin[sic] on the original graph is maintaned[sic] in the object tracker, but in order to return entities with entity refs and sets we would need to pull everything that is reachable. The information on modified members comes from the current graph, which actually exists in memory independently of the object tracker.

    We have also verified that no spurious inserts are issued when SubmitChanges() is invoked after calling GetOriginalEntityState().

    Thanks for reporting this.

    The LINQ to SQL Team

    The bug’s Status remains Active.

    Unlike wine and whiskey, bug reports do not improve with age.

    Thursday, November 20, 2008

    Azure Storage Services Test Harness: Table Services 4 – Programming the Table Services API

    Update 1/31/2009: Code is now available for download.

    This is the fourth of a series of articles about a ASP.NET 3.5 C# test harness for Azure Storage Services that is will be available for download from my “Retire Your Data Center” cover story for Visual Studio Magazine’s February 2009 issue (click the Get Code Download link) in the near future.

    The Microsoft.Samples.ServiceHosting.StorageClient namespace consists of helper classes contained in nine *.cs class files of which two—TableStorage.cs and StorageAccountInfo.cs contain classes used by the classes that define the central EntityNameDataModel and EntityNameDataServiceContext classes where EntityName = Customer for this example.

    Preceding episodes of this series are:

    The following two sections contain code that defines the CustomerDataModel class and the CustomerServiceContext class.

    The EntityNameDataModel Class

    The LINQ In-Memory Object Generator (LIMOG) v2 program (see Azure Storage Services Test Harness: Table Services 5 – Generating the Collection Initializer with LIMOG v2) autogenerates the EntityNameDataModel class from the selected data table. This class derives from the TableStorageEntity abstract class in TableStorage.cs:

    The Customers table’s properties are all of the string type; LIMOG v2 generates similar classes for other tables with more divergent data types as well as classes for SQL Data Services (SDS) containers.

    Following is a partial screen capture of LIMOG v2’s collection initializer for the CustomerTable with the RowKey equal to the CustomerID value:

    The EntityNameDataService Class

    The EntityNameDataService class inherits the TableStorageDataServiceContext class from TableService.cs. Its constructor requires an argument of the StorageAccountInfo class, which is defined in the StorageAccountInfo.cs file.

    The later “TableStorage.cs Classes in the StorageClient Assembly” and The “StorageAccountInfo Class” sections have TableServices and StorageAccountInfo class diagram screen captures.

    An customerData ObjectDataSource control binds to the CustomerDataSource class and its Select(), Insert(), and Delete() methods to support the Default.aspx Web page’s bound DataView and FormView controls:

    The GridView displays only a few columns to enable exposing the PartitionKey and RowKey values without horizontal scrolling:

    TableStorage.cs Classes in the StorageClient Assembly

    The StorageClient assembly is a set of .NET wrapper classes for REST operations of the Table Storage, Blog Storage and Queue APIs. The assembly lets developers use the ADO.NET Data Services’ .NET Client library (System.Data.Services.Client)

    The StorageInfo Class

    The next episode in this series is Azure Storage Services Test Harness: Table Services 5 – Generating the Collection Initializer with LIMOG v2.

    Azure Storage Services Test Harness: Table Services 3 –Starting the Test Harness Project

    Update 1/31/2009: Code is now available for download.

    This is the third of a series of articles about a ASP.NET 3.5 C# test harness for Azure Storage Services that is will be available for download from my “Retire Your Data Center” cover story for Visual Studio Magazine’s February 2009 issue (click the Get Code Download link) in the near future.

    Here are links to the earlier episodes in this series:

    Installing Windows Azure Tools for Visual Studio 1.0 adds Cloud Service and CloudWorkflow project types and installs four Cloud Service templates. To create an ASP.NET Web Application that uses Azure Table Services as a data source, select a Cloud Service project and the Web Cloud Service template:

    Note: For a more detailed description of the setup process for a simple project, take Jim Nakashima’s Windows Azure Walkthrough: Simple Table Storage of 10/28/2008. If you haven’t done so already, take Jim’s Video Walkthrough: A Quick Lap around Windows Azure Tools for Microsoft Visual Studio of 10/28/2008 before starting the Table Storage project. This post covers steps 1 through 6 of Jim’s walkthrough.

    The Web Cloud Service template adds the Cloud Service project (*.ccproj) with a Roles folder, which contains a pointer to an added Web Cloud Service ProjectName_WebRole project that contains the ASP.NET client components. The *.ccproj file contains ServiceConfiguration.cscfg and ServiceDefinition.csdef files. By default, the ServiceConfiguration is set to Development Fabric and Development Storage.

    References to the Microsoft.ServiceHosting.ServiceRuntime and System.Data.Services.Client (ADO.NET Data Services [Astoria] Client) namespaces are added automatically to the ProjectName_WebRole project.

    You must also add references to the ProjectName_WebRole’s Common.dll and StorageClient.dll helper assemblies; these two assemblies and their sample code are contained in the \Program Files\Windows Azure SDK\1.0\samples.zip file. Their source code and DLLs have been copied into the test harness project’s source code to support portability. (Class diagrams are optional.)

    Common.dll and StorageClient.dll are sample, not official, libraries for Azure application developers. Here’s Aleks Gershaft’s (Microsoft) response to Wayne Walter Berry’s Understanding the Role of StorageClient in Our Application thread of 11/20/2009 in the Windows Azure forum:

    The current version of StorageClient is provided as a sample for the developers and should not be considered an official library. The documentation has the following disclaimer:

    The StorageClient sample library is not optimized for performance and is not intended to be used for building robust services, but only as an example of a working client library.

    We are not ready to announce any future plans with respect to any official library.
    Note: We consider the REST APIs to be the official APIs for Windows Azure storage and therefore any changes in those will be done with minimal impact on existing code.

    The next episode in this series is: Azure Storage Services Test Harness: Table Services 4 – Programming the Table Services API.

    Tuesday, November 18, 2008

    Azure Storage Services Test Harness: Table Services 2 – the Table Services API

    Update 1/31/2009: Code is now available for download.

    This is the second of a series of articles about a ASP.NET 3.5 C# test harness for Azure Storage Services that is will be available for download from my “Retire Your Data Center” cover story for Visual Studio Magazine’s February 2009 issue (click the Get Code Download link) in the near future.

    Note: The Azure Storage Services Test Harness: Table Services 1 – Introduction and Overview describes the test harness for the Customers table and Azure Table Storage services.

    The Table Storage API defines structured storage for Table objects that contain Entity objects, both of which you manipulate by Representational State Transfer (REST) methods with Atom feed documents. Atom feeds conform to the Atom Publication (AtomPub) API and ADO.NET Data Services Framework’s Atom Serialization Rules. The API doesn’t support the JavaScript Object Notation (JSON) wire format.

    Note: Although Table Storage API documentation mentions ADO.NET Data Services (Astoria) frequently, Table and Entity objects don’t implement the complete Astoria runtime. For example, Table Services doesn’t support $orderby or $skip query string options, but it does respect the $top=n option when you apply the Top(n) operator and $filter=querystring for a Where clause in LINQ to REST queries.

    The API supports a $ct=LastPartitionKey/LastRowKey (continuation token) query string option to specify the initial entity for paging query EntitySets, which takes the place of the $skip option.

    REST Operations on Tables

    The API defines the following REST operations on Tables:

    Create Table

    The following HTTP POST request creates a CustomerTable if it doesn’t exist. This operation runs from code in the Global.asax.cs file’s Application_BeginRequest event handler*:

    POST http://oakleaf.table.core.windows.net/Tables
    POST /Tables HTTP/1.1
    User-Agent: Microsoft ADO.NET Data Services
    x-ms-date: Mon, 10 Nov 2008 16:06:02 GMT
    Authorization: SharedKeyLite oakleaf:eRbDw5U7BkeSfZmKj71Zy3WTjrZCWkseVav3NK3tVqA=
    Accept: application/atom+xml,application/xml
    Accept-Charset: UTF-8
    DataServiceVersion: 1.0;NetFx
    MaxDataServiceVersion: 1.0;NetFx
    Content-Type: application/atom+xml
    Host: oakleaf.table.core.windows.net
    Content-Length: 499
    Expect: 100-continue
    Proxy-Connection: Keep-Alive
    
    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
        xmlns="http://www.w3.org/2005/Atom">
      <title />
      <updated>2008-11-10T16:06:02.1557288Z</updated>
      <author>
        <name />
      </author>
      <id />
      <content type="application/xml">
        <m:properties>
          <d:TableName>CustomerTable</d:TableName>
        </m:properties>
      </content>
    </entry>

    *Handling the Application_BeginRequest (rather than the Application_Start) event is required because Windows Azure runs IIS 7 in Integrated mode, which throws an exception if attempted in the latter handler. (See Mike Volodarsky’s IIS7 Integrated mode: Request is not available in this context exception in Application_Start post of 11/10/2007.)

    Notes: The maximum skew between the x-ms-date value and server UTC is 15 minutes. Blob Storage, Table Storage, and Queue support the SharedKey authentication scheme. The key signature is a Hash Message Authentication Code (HMAC) constructed from the request and computed with the SHA256 algorithm, then encoded using Base64 encoding. The ADO.NET Data Services’ .NET Client library (System.Data.Services.Client) supports a simpler SharedKeyLite authentication scheme only.

    If the table doesn’t exist, the project creates an empty table. If the table exists, the POST attempt sends the following error response:

    HTTP/1.1 409 The table specified already exists.
    Cache-Control: no-cache
    Content-Length: 258
    Content-Type: application/xml
    Server: Table Service Version 1.0 Microsoft-HTTPAPI/2.0
    x-ms-request-id: 7b66eaa7-68f4-4926-ae43-579074b71c04
    Date: Mon, 10 Nov 2008 16:05:50 GMT
    
    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
      <code>TableAlreadyExists</code>
      <message xml:lang="en-US">The table specified already exists.</message>
    </error>

    Query Tables

    Here’s the request to return a list of table names as an IEnumerable<string> type:

    GET http://myaccount.table.core.windows.net/Tables
    GET /Tables() HTTP/1.1
    User-Agent: Microsoft ADO.NET Data Services
    x-ms-date: Tue, 11 Nov 2008 00:27:35 GMT
    Authorization: SharedKeyLite oakleaf:J6YsUkLyrkHc5DW63K/NGQakgaQge+RfMfcIfMwRGf8=
    Accept: application/atom+xml,application/xml
    Accept-Charset: UTF-8
    DataServiceVersion: 1.0;NetFx
    MaxDataServiceVersion: 1.0;NetFx
    Host: oakleaf.table.core.windows.net

    And here’s the response:

    HTTP/1.1 200 OK
    Cache-Control: no-cache
    Content-Type: application/atom+xml;charset=utf-8
    Server: Table Service Version 1.0 Microsoft-HTTPAPI/2.0
    x-ms-request-id: e7f01114-bd1e-47c3-9c85-26b12080f30c
    Date: Tue, 11 Nov 2008 00:28:55 GMT
    Content-Length: 1036
    
    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <feed xml:base="http://oakleaf.table.core.windows.net/" 
        xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
        xmlns="http://www.w3.org/2005/Atom">
      <title type="text">Tables</title>
      <id>http://oakleaf.table.core.windows.net/Tables</id>
      <updated>2008-11-11T00:28:56Z</updated>
      <link rel="self" title="Tables" href="Tables" />
      <entry>
        <id>http://oakleaf.table.core.windows.net/Tables('CustomerTable')</id>
        <title type="text"></title>
        <updated>2008-11-11T00:28:56Z</updated>
        <author>
          <name />
        </author>
        <link rel="edit" title="Tables" href="Tables('CustomerTable')" />
        <category term="oakleaf.Tables"
           scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
        <content type="application/xml">
          <m:properties>
            <d:TableName>CustomerTable</d:TableName>
          </m:properties>
        </content>
      </entry>
    </feed>

    Delete Table

    Deleting a table is much faster than removing all entities and starting over. Here’s the request:

    DELETE http://oakleaf.table.core.windows.net/Tables('CustomerTable')
    DELETE /Tables('CustomerTable') HTTP/1.1
    User-Agent: Microsoft ADO.NET Data Services
    x-ms-date: Tue, 11 Nov 2008 01:04:28 GMT
    Authorization: SharedKeyLite oakleaf:Y8hQOQjVqshUUif6E/gKDIB0Ga0rD5P7ENOHsmcAqAs=
    Accept: application/atom+xml,application/xml
    Accept-Charset: UTF-8
    DataServiceVersion: 1.0;NetFx
    MaxDataServiceVersion: 1.0;NetFx
    Content-Type: application/atom+xml
    Host: oakleaf.table.core.windows.net
    Content-Length: 0

    and the response:

    HTTP/1.1 204 No Content
    Cache-Control: no-cache
    Content-Length: 0
    Server: Table Service Version 1.0 Microsoft-HTTPAPI/2.0
    x-ms-request-id: 9e047535-cf33-4bbc-8a83-fa4472e36c65
    Date: Tue, 11 Nov 2008 01:05:50 GMT

    REST Operations on Entities

    The Table API Supports the following REST operations on entities:

    Insert Entity (HTTP POST)

    Following is the HTTP POST request to insert a single Customer entity:

    POST http://oakleaf.table.core.windows.net/CustomerTable
    POST /CustomerTable HTTP/1.1
    User-Agent: Microsoft ADO.NET Data Services
    x-ms-date: Mon, 10 Nov 2008 16:43:18 GMT
    Authorization: SharedKeyLite oakleaf:9G5cV5Ad9HVu55GEwIq524OtgK1YI5Tq8IxYn25y8AY=
    Accept: application/atom+xml,application/xml
    Accept-Charset: UTF-8
    DataServiceVersion: 1.0;NetFx
    MaxDataServiceVersion: 1.0;NetFx
    Content-Type: application/atom+xml
    Host: oakleaf.table.core.windows.net
    Content-Length: 1083
    Expect: 100-continue
    
    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
      <title />
      <updated>2008-11-10T16:43:18.802576Z</updated>
      <author>
        <name />
      </author>
      <id />
      <content type="application/xml">
        <m:properties>
          <d:Address>Obere Str. 57</d:Address>
          <d:City>Berlin</d:City>
          <d:CompanyName>Alfreds Futterkiste</d:CompanyName>
          <d:ContactName>Maria Anders</d:ContactName>
          <d:ContactTitle>Sales Representative</d:ContactTitle>
          <d:Country>Germany</d:Country>
          <d:CustomerID>ALFKI</d:CustomerID>
          <d:Fax>030-0076545</d:Fax>
          <d:PartitionKey>Customers</d:PartitionKey>
          <d:Phone>030-0074321</d:Phone>
          <d:PostalCode>12209</d:PostalCode>
          <d:Region m:null="true" />
          <d:RowKey>ALFKI</d:RowKey>
          <d:Timestamp m:type="Edm.DateTime">0001-01-01T00:00:00</d:Timestamp>
        </m:properties>
      </content>
    </entry>

    and the response:

    HTTP/1.1 201 Created
    Cache-Control: no-cache
    Transfer-Encoding: chunked
    Content-Type: application/atom+xml;charset=utf-8
    ETag: W/"datetime'2008-11-10T16%3A43%3A09.274Z'"
    Location: http://oakleaf.table.core.windows.net/CustomerTable(PartitionKey='Customers',RowKey='ALFKI')
    Server: Table Service Version 1.0 Microsoft-HTTPAPI/2.0
    x-ms-request-id: 315d2a3c-32a7-405f-b967-2a6d7c7774a2
    Date: Mon, 10 Nov 2008 16:43:08 GMT
    
    5D6
    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <entry xml:base="http://oakleaf.table.core.windows.net/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:etag="W/&quot;datetime'2008-11-10T16%3A43%3A09.274Z'&quot;" xmlns="http://www.w3.org/2005/Atom">
      <id>http://oakleaf.table.core.windows.net/CustomerTable(PartitionKey='Customers',RowKey='ALFKI')</id>
      <title type="text"></title>
      <updated>2008-11-10T16:43:09Z</updated>
      <author>
        <name />
      </author>
      <link rel="edit" title="CustomerTable" href="CustomerTable(PartitionKey='Customers',RowKey='ALFKI')" />
      <category term="oakleaf.CustomerTable" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
      <content type="application/xml">
        <m:properties>
          <d:PartitionKey>Customers</d:PartitionKey>
          <d:RowKey>ALFKI</d:RowKey>
          <d:Timestamp m:type="Edm.DateTime">2008-11-10T16:43:09.274Z</d:Timestamp>
          <d:Address>Obere Str. 57</d:Address>
          <d:City>Berlin</d:City>
          <d:CompanyName>Alfreds Futterkiste</d:CompanyName>
          <d:ContactName>Maria Anders</d:ContactName>
          <d:ContactTitle>Sales Representative</d:ContactTitle>
          <d:Country>Germany</d:Country>
          <d:CustomerID>ALFKI</d:CustomerID>
          <d:Fax>030-0076545</d:Fax>
          <d:Phone>030-0074321</d:Phone>
          <d:PostalCode>12209</d:PostalCode>
        </m:properties>
      </content>
    </entry>
    0

    Query Entities (HTTP GET)

    Following is the GET request header for the first eight CustomerTable entities:

    GET http://oakleaf.table.core.windows.net/CustomerTable()?$top=8
    GET /CustomerTable()?$top=8 HTTP/1.1
    User-Agent: Microsoft ADO.NET Data Services
    x-ms-date: Mon, 10 Nov 2008 16:06:02 GMT
    Authorization: SharedKeyLite oakleaf:lk0wzp7lph5a/CdBBekQnwgFkIz0ZUG0Xr3qsWZEFWs=
    Accept: application/atom+xml,application/xml
    Accept-Charset: UTF-8
    DataServiceVersion: 1.0;NetFx
    MaxDataServiceVersion: 1.0;NetFx
    Host: oakleaf.table.core.windows.net

    and the response (without the AtomPub body)

    HTTP/1.1 200 OK
    Cache-Control: no-cache
    Content-Type: application/atom+xml;charset=utf-8
    Server: Table Service Version 1.0 Microsoft-HTTPAPI/2.0
    x-ms-request-id: 6c5e2432-1b60-4d56-8915-37b4b1edd375
    x-ms-continuation-NextPartitionKey: Customers
    x-ms-continuation-NextRowKey: BONAP
    Date: Mon, 10 Nov 2008 16:05:50 GMT
    Content-Length: 10752

    A query returns a maximum of 1,000 rows. The NextPartitionKey and NextRowKey values are used for paging results.

    Update or Merge Entity (HTTP PUT or MERGE)

    The HTTP PUT method deletes and recreates the entity. The MERGE method enables replacing individual property values:

    MERGE http://oakleaf.table.core.windows.net/CustomerTable(PartitionKey="Customers", RowKey="ALFKI") 
    MERGE /CustomerTable(PartitionKey='Customers',RowKey='ALFKI') HTTP/1.1
    User-Agent: Microsoft ADO.NET Data Services
    x-ms-date: Mon, 10 Nov 2008 17:34:17 GMT
    Authorization: SharedKeyLite oakleaf:uKKpW70RiQI0mio90bXkBJ2CxZX5bHhhQQRHuxNXG3Q=
    Accept: application/atom+xml,application/xml
    Accept-Charset: UTF-8
    DataServiceVersion: 1.0;NetFx
    MaxDataServiceVersion: 1.0;NetFx
    Content-Type: application/atom+xml
    If-Match: W/"datetime'2008-11-10T16%3A43%3A09.274Z'"
    Host: oakleaf.table.core.windows.net
    Content-Length: 1194
    Expect: 100-continue
    
    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
      <title />
      <updated>2008-11-10T17:34:17.1314394Z</updated>
      <author>
        <name />
      </author>
      <id>http://oakleaf.table.core.windows.net/CustomerTable(PartitionKey='Customers',RowKey='ALFKI')</id>
      <content type="application/xml">
        <m:properties>
          <d:Address>Obere Str. 57</d:Address>
          <d:City>Berlin</d:City>
          <d:CompanyName>Alfreds Futterkiste (Updated)</d:CompanyName>
          <d:ContactName>Maria Anders</d:ContactName>
          <d:ContactTitle>Sales Representative</d:ContactTitle>
          <d:Country>Germany</d:Country>
          <d:CustomerID>ALFKI</d:CustomerID>
          <d:Fax>030-0076545</d:Fax>
          <d:PartitionKey>Customers</d:PartitionKey>
          <d:Phone>030-0074321</d:Phone>
          <d:PostalCode>12209</d:PostalCode>
          <d:Region m:null="true" />
          <d:RowKey>ALFKI</d:RowKey>
          <d:Timestamp m:type="Edm.DateTime">2008-11-10T16:43:09.274Z</d:Timestamp>
        </m:properties>
      </content>
    </entry>

    Here are the response headers with the updated Timestamp value in the ETag header:

    HTTP/1.1 204 No Content
    Cache-Control: no-cache
    Content-Length: 0
    ETag: W/"datetime'2008-11-10T17%3A35%3A18.6307782Z'"
    Server: Table Service Version 1.0 Microsoft-HTTPAPI/2.0
    x-ms-request-id: 7687059d-ab33-4c88-bc7b-1aadb6aab331
    Date: Mon, 10 Nov 2008 17:34:14 GMT

    Delete Entity (HTTP DELETE)

    Delete a single entity with the following DELETE request header:

    DELETE http://oakleaf.table.core.windows.net/CustomerTable(PartitionKey="Customers", RowKey="ALFKI") 
    DELETE /CustomerTable(PartitionKey='Customers',RowKey='ALFKI') HTTP/1.1
    User-Agent: Microsoft ADO.NET Data Services
    x-ms-date: Mon, 10 Nov 2008 16:35:57 GMT
    Authorization: SharedKeyLite oakleaf:PMEUEMoho1GjyedXSeLzfynWUx9OP/oPRad2sO9dgqk=
    Accept: application/atom+xml,application/xml
    Accept-Charset: UTF-8
    DataServiceVersion: 1.0;NetFx
    MaxDataServiceVersion: 1.0;NetFx
    Content-Type: application/atom+xml
    If-Match: W/"datetime'2008-11-10T00%3A53%3A39.2200295Z'"
    Host: oakleaf.table.core.windows.net
    Content-Length: 0

    and receive this response header:

    HTTP/1.1 204 No Content
    Cache-Control: no-cache
    Content-Length: 0
    Server: Table Service Version 1.0 Microsoft-HTTPAPI/2.0
    x-ms-request-id: d1f0cf12-d82c-4e77-b67b-64ce8494a534
    Date: Mon, 10 Nov 2008 16:35:30 GMT

    Updated 11/18/2008 for a modification that runs the CreateTablesFromModel() method from the Application_BeginRequest event handler instead of for every operation. See Steve Marx’s Try to Create Tables Only Once post of 11/18/2008.

    The next episode in this series is Azure Storage Services Test Harness: Table Services 3 –Starting the Test Harness Project of 11/20/2008.