Compartir a través de


Linq to REST

Late Sunday night we released the first public preview of ASP.NET 3.5 Extensions.  For information on the release, see ScottGu's announcement.

As part of that preview, we released the first CTP of the production version of Project Astoria.  For details, see public release announcement by Mike Flasko on the Astoria Team Blog.

Astoria actually has been given its official Microsoft name:  ADO.NET Data Services.  So, in this post I will use the name Astoria and ADO.net Data Services interchangeably.

For a complete overview of Astoria check out the information available on Microsoft Live Labs.

For the next few weeks, I will be writing a series of blog posts to demonstrate what I think is one of the most compelling features in Astoria, namely remote execution of Linq queries via the RESTFUL API exposed by Astoria Data Services.

For these posts, I will be covering:

1)  How to set up an Astoria Data Service which can be used for remote execution of Linq queries.

2)  Dive deep into the Astoria Client API's Linq support including a detailed description of how Linq queries are translated to URIs.

3)  How to make the Astoria Data Service updateable so the results of the Linq queries can be remotely modified and persisted.

So the goal of this initial post is to set up an Astoria Data Service over a Linq to Sql DataContext source and remotely execute a Linq query via the Astoria client library over HTTP.

(The following steps assume Visual Studio 2008 and ASP.NET 3.5 Extensions has been installed.  Also, this demo assumes access to the Sql Server sample Northwind database).

First, Create a standard ASP.NET Web Application:

image 

Next, add an ADO.NET Data Service called Northwind.svc to the project via the Add New Item option:

image 

Next, add a new set of Linq to Sql via the designer called Northwind.dbml.

image  

From my Data Connections in the Server Explorer, I add the Categories, Products, and Supplier tables to Northwind.dbml from the Northwind database

image

Because the keys for the new types follow the Astoria convention of being named [EntityName]Id, I don't have to do anything further.  The Linq to Sql data classes and the strongly typed DataContext (NorthwindDataContext) is totally useable with Astoria without any modifications.

Next, I want to wire up my Astoria Data Service to use NorthwindDataContext as the data source.  To do this, go back to the Northwind.svc.cs file that was created when the Astoria Data Service was added to the project.  Look for the TODO's in the Northwind class:

  
     public class Northwind : WebDataService< /* TODO: put your data source class name here */ >
    {
        // This method is called once during service initialization to allow
        // service-specific policies to be set
        public static void InitializeService(IWebDataServiceConfiguration config)
        {
            // TODO: set rules to indicate which entity sets and service operations are
            // visible, updatable, etc.
            // (for testing purposes use "*" to indicate all entity sets/service
            // operations, but that option should NOT be used in production systems)

            // Example for entity sets (this example uses "AllRead" which allows reads but not writes)
            // config.SetResourceContainerAccessRule("MyEntityset", ResourceContainerRights.AllRead);

            // Example for service operations
            // config.SetServiceOperationAccessRule("MyServiceOperation", ServiceOperationRights.All);
        }

        // Query interceptors, change interceptors and service operations go here
    }

First, put the name of the DataContext in as the generic parameter for the Northwind class.

Next. add the following line to the InitializeService method:

 config.SetResourceContainerAccessRule("*", ResourceContainerRights.AllRead);

By default, Astoria turns off all access to the data source.  By adding this line, I am giving read access to all public IQueryable<T> entry points on the DataContext. 

Note, the wildcard option (*) should only be used for testing purposes.  For actual application development, please explicitly grant access to each IQueryable<T> entry point by via the property name.

Now build the application and press F5 to fire it up.  If everything went ok, you should get back the following Atom service definition when you access the URI https://localhost:18752/Northwind.svc/ (I am using port 18752 with Cassini for debugging).

 

   <service xml:base="https://localhost:18752/Northwind.svc/" xmlns:atom="https://www.w3.org/2005/Atom" xmlns:app="https://www.w3.org/2007/app" xmlns="https://www.w3.org/2007/app">
    <workspace>
       <atom:title>Default</atom:title> 
       <collection href="Categories">
         <atom:title>Categories</atom:title> 
       </collection>
       <collection href="Products">
         <atom:title>Products</atom:title> 
       </collection>
       <collection href="Suppliers">
         <atom:title>Suppliers</atom:title> 
       </collection>
    </workspace>
  </service>

 

Now, try a few URIs to make sure everything it working:

(Note, Internet Explorer by default renders ATOM in a friendly format that makes Astoria feeds unreadable.  To fix this, turn off IE feed viewing by turning off the option :  Tools -> Internet Options -> Content ->  Feeds (settings) -> Turn on feed viewing)

https://localhost:18752/Northwind.svc/Products - gets all the Products

https://localhost:18752/Northwind.svc/Products(2) - gets the Product with ProductId == 2

https://localhost:18752/Northwind.svc/Products?$filter=UnitsInStock gt 100 - gets all the Products where UnitsInStock is greater than 100

https://localhost:18752/Northwind.svc/Products?$orderby=ProductName&$top=10 - orders the Products by ProductName and gets the first 10.

 

For more information about Astoria's URI Addressing Scheme see here.

Now, lets get a sample Linq query working.

First, add another project to the solution.  In this case, a simple console Application will work:

image

In this project, add a reference to the Astoria client library assembly called Microsoft.Data.WebClient.dll. It should be in your /Program Files/Reference Assemblies/Microsoft/Framework/ASP.NET 3.5 Extensions directory.

Now add make sure the namespace Microsoft.Data.WebClient is in scope, and add the following class to your project:

 

     [OpenObject("PropBag")]
    public class Product
    {
        private Dictionary<string, object> propBag = new Dictionary<string, object>();

        [Key]
        public int ProductID { get; set; }
        
        public string ProductName { get; set; }
        
        public int UnitsInStock { get; set; }

        public IDictionary<string, object> PropBag { get { return propBag; } }

    }

Finally, add the following to Program.Main:

  
         static void Main(string[] args)
        {
            WebDataContext context = new WebDataContext("https://localhost:18752/Northwind.svc");

            var query = from p in context.CreateQuery<Product>("Products")
                        where p.UnitsInStock > 100
                        select p;

            foreach (Product p in query)
            {
                Console.WriteLine(p.ProductName + " , UnitsInStock= " + p.UnitsInStock);
            }

        }

 

To get both projects to start up for debugging, select Solution-> Properties and select Multiple startup projects with the Action of Start.

Put a breakpoint on the foreach statement in the client app, and hit F5.

image

If you hover over the query variable, you will actually see the Astoria URI which the Linq query is translated into by the Astoria client library:

https://localhost:18752/Northwind.svc/Products?$filter=(UnitsInStock)%20gt%20(100)

So, there you go.  Linq to Astoria's RESTFUL API.  In other words, Linq to REST. 

In future posts, I will explain how that worked.  What all the Linq capabilities that are supported.  And what one can do with the objects once they are materialized.

Comments

  • Anonymous
    December 10, 2007
    PingBack from http://www.absolutely-people-search.info/?p=5514
  • Anonymous
    December 10, 2007
    While we worked hard to make it such that any HTTP client can easily consume an ADO.NET Data Service,
  • Anonymous
    December 10, 2007
    While we worked hard to make it such that any HTTP client can easily consume an ADO.NET Data Service
  • Anonymous
    December 11, 2007
    The latest Astoria / ADO.NET Data Services CTP also includes a client-side library with support for creating...
  • Anonymous
    December 11, 2007
    Is there a trick to get Linq to Sql DataContext to work with the Data Service?  I was not able to get my Linq to Sql context to work.
  • Anonymous
    December 11, 2007
    No trick.  What issue are you having?
  • Anonymous
    December 11, 2007
    Link Listing - December 11, 2007
  • Anonymous
    December 12, 2007
    Prodded by Mike to pick up the slack, I am trying to get one of these out each morning before all my
  • Anonymous
    December 12, 2007
    You've been kicked (a good thing) - Trackback from DotNetKicks.com
  • Anonymous
    December 13, 2007
    I had to add DataWebKeyAttribute to my primary keys to get the data.svc default page to show anything.  Then when i do data.svc/entity, i don't get anything.  Is there some pattern it is looking for?  
  • Anonymous
    December 13, 2007
    Did you modify the InitializeService method in your data service to allow access to your EntitySets?
  • Anonymous
    December 13, 2007
    The comment has been removed
  • Anonymous
    December 13, 2007
    Linq to REST 正確にはLINQ to ADO.NET Data Services のようです。 で、これを使うとADO.NET Data Servicesが提供するデータの取得/追加/更新/削除ができるようですね。...
  • Anonymous
    December 14, 2007
    This worked fine for reading. I had an issues with getting it working for the update of an entity. I got an server erorr when updating with AppendOnly Tracking.Any ideas?
  • Anonymous
    December 18, 2007
    こんにちは、こだかです。 オフラインセミナーも終わりまして、ようやく新しい情報をキャッチアップできるようにと思っていた矢先ですが、前述のVS2008のイベント準備などもあり、思うように時間がとれません。
  • Anonymous
    December 18, 2007
    こんにちは、こだかです。 オフラインセミナーも終わりまして、ようやく新しい情報をキャッチアップできるようにと思っていた矢先ですが、前述のVS2008のイベント準備などもあり、思うように時間がとれません
  • Anonymous
    December 18, 2007
    Tim - to get updating to work over Linq to Sql you will need to implement IUpdateable for your DataContext.  I am planning a post in the near future to show how to do this.
  • Anonymous
    January 28, 2008
    Thanks to everyone who came to my session, hope you enjoyed it. First off, instead of slides I used WPF
  • Anonymous
    February 11, 2008
    Steve Herbert has an interesting performance evaluation discussion up on his blog (this is raw LINQ,
  • Anonymous
    March 26, 2008
    Someone emailed me recently saying that they couldn’t find enough examples in .NET for talking to the
  • Anonymous
    August 05, 2008
    The comment has been removed
  • Anonymous
    December 02, 2008
    Prodded by Mike to pick up the slack, I am trying to get one of these out each morning before all my work REST/Astoria/Web Programming/Web Services Christian shows how to access SSDL (ADO.NET Entity Framework's s tore s chema d efinition l anguage and
  • Anonymous
    January 15, 2009
    I've given a number of presentations on ADO.NET Data Services (formerly codenamed: &quot;Astoria&quot;)