かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

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>

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