かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

WCF Data Services リフレクションプロバイダー使ってみよう

WCF Data Servicesの記事を見ると、どれもEntity FrameworkのObjectContextやDbContextをベースにしたクラスを前提にしているものが多いので、ここではあえてリフレクションプロバイダーを使って頑張ってみようと思います。リフレクションプロバイダーを使うと以下のようなイメージのことが出来ると信じてます。

これが出来なかったら悲しみますはい。

リフレクションプロバイダーとは

WCF Data Servicesのリフレクションプロバイダーは、IQueryableのプロパティを提供するPOCOをSystem.Data.Services.DataServiceのTの部分に指定して作成したときに使われる奴です。例えば、こんなコードで簡単にEntity Frameworkを使わなくてもODataのデータを公開できます。

namespace WebApplication1
{
    using System.Collections.Generic;
    using System.Data.Services;
    using System.Data.Services.Common;
    using System.Linq;

    public class WcfDataService : DataService<SampleContext>
    {
        public static void InitializeService(DataServiceConfiguration config)
        {
            config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
        }
    }

    // PersonとAddressを公開するクラス
    public class SampleContext
    {
        public IQueryable<Person> People
        {
            get { return Person.Source.AsQueryable(); }
        }

        public IQueryable<Address> Addresses
        {
            get { return Person.Source.Select(p => p.Address).AsQueryable(); }
        }
    }

    [DataServiceKey("Id")]
    public class Person
    {
        // テスト用データ
        public static readonly List<Person> Source = Enumerable.Range(1, 10)
            .Select(i =>
                new Person
                {
                    Id = i,
                    Name = "test data " + i,
                    Address = new Address { Id = i, City = "test city " + i }
                })
            .ToList();

        public int Id { get; set; }
        public string Name { get; set; }

        public Address Address { get; set; }
    }

    [DataServiceKey("Id")]
    public class Address
    {
        public int Id { get; set; }
        public string City { get; set; }
    }
}

WcfDataService.svcを開始ページに設定してアプリケーションを実行すると、以下のようなXMLが表示されます。

<?xml version="1.0" encoding="utf-8"?>
<service xml:base="http://localhost:49533/WcfDataService.svc/" xmlns="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom">
  <workspace>
    <atom:title>Default</atom:title>
    <collection href="People">
      <atom:title>People</atom:title>
    </collection>
    <collection href="Addresses">
      <atom:title>Addresses</atom:title>
    </collection>
  </workspace>
</service>

この状態で、ODataのクエリを投げるとちゃんとデータが取れる状態にまでなってます。例えば” http://localhost:49533/WcfDataService.svc/People(1)?$expand=Address”のようなURLにGETをすると以下のようなデータが返ってきます。

<?xml version="1.0" encoding="utf-8"?>
<entry xml:base="http://localhost:49533/WcfDataService.svc/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
  <id>http://localhost:49533/WcfDataService.svc/People(1)</id>
  <category term="WebApplication1.Person" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
  <link rel="edit" title="Person" href="People(1)" />
  <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Address" type="application/atom+xml;type=entry" title="Address" href="People(1)/Address">
    <m:inline>
      <entry>
        <id>http://localhost:49533/WcfDataService.svc/Addresses(1)</id>
        <category term="WebApplication1.Address" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
        <link rel="edit" title="Address" href="Addresses(1)" />
        <title />
        <updated>2012-10-02T11:50:11Z</updated>
        <author>
          <name />
        </author>
        <content type="application/xml">
          <m:properties>
            <d:Id m:type="Edm.Int32">1</d:Id>
            <d:City>test city 1</d:City>
          </m:properties>
        </content>
      </entry>
    </m:inline>
  </link>
  <title />
  <updated>2012-10-02T11:50:11Z</updated>
  <author>
    <name />
  </author>
  <content type="application/xml">
    <m:properties>
      <d:Id m:type="Edm.Int32">1</d:Id>
      <d:Name>test data 1</d:Name>
    </m:properties>
  </content>
</entry>

公開だけならとってもお手軽なんですよね。さて、ここにロジックを挟み込んでみようと思うのが本題…。ちょっと悩もう。