WCF Webプログラミングモデルの学習テスト Part3

今日はWCF 配信の学習テスト。AtomフィードRSSフィードをどのように提供するかについて。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Syndication;
using System.ServiceModel.Web;
using System.Xml;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace LearningWCFTests
{
    [TestClass]
    public class SyndicationFeedTest
    {
        ...

        [ServiceContract]
        public interface ICustomers
        {
            [OperationContract]
            [WebGet(UriTemplate = "customers?format={format}")]
            [ServiceKnownType(typeof(Atom10FeedFormatter))]
            [ServiceKnownType(typeof(Rss20FeedFormatter))]
            SyndicationFeedFormatter GetCustomers(string format);

            [OperationContract]
            [WebGet(UriTemplate = "customers/{id}?format={format}")]
            [ServiceKnownType(typeof(Atom10FeedFormatter))]
            [ServiceKnownType(typeof(Rss20FeedFormatter))]
            SyndicationFeedFormatter GetCustomer(string id, string format);
        }

        [DataContract]
        public class Customer
        {
            [DataMember]
            public string Id { get; set; }

            [DataMember]
            public string Name { get; set; }

            [DataMember]
            public string Address { get; set; }

            public override string ToString()
            {
                return String.Format("{0}, {1}, {2}", Id, Name, Address);
            }
        }

        public class Customers : ICustomers
        {
            private List<Customer> customers_ = new List<Customer>() 
            {
                new Customer() { Id = "1", Name = "Alice", Address = "123 Pike Place" },
                new Customer() { Id = "2", Name = "Bob", Address = "12323 Lake Shore Drive" },
                new Customer() { Id = "3", Name = "John", Address = "4545 Wacker Drive" }
            };

            public SyndicationFeedFormatter GetCustomers(string format)
            {
                return CreateFeedFormatterFrom(customers_, format);
            }

            public SyndicationFeedFormatter GetCustomer(string id, string format)
            {
                return CreateFeedFormatterFrom(
                    from customer in customers_
                    where customer.Id == id
                    select customer, 
                    format);
            }

            private SyndicationFeedFormatter CreateFeedFormatterFrom(IEnumerable<Customer> customers, string format)
            {
                UriTemplateMatch match = WebOperationContext.Current.IncomingRequest.UriTemplateMatch;
                UriTemplate template = new UriTemplate("customers");

                SyndicationFeed feed = new SyndicationFeed() 
                { 
                    Id = template.BindByPosition(match.BaseUri).ToString(),
                    Title = SyndicationContent.CreatePlaintextContent("Customers"),
                    LastUpdatedTime = DateTimeOffset.Now
                };
                feed.Links.Add(new SyndicationLink() 
                    { Uri = template.BindByPosition(match.BaseUri), RelationshipType = "self", Title = "Customers" });
                feed.Items = from customer in customers
                    select GetSyndicationItemFrom(customer);

                if (format == "atom")
                    return new Atom10FeedFormatter(feed);
                else
                    return new Rss20FeedFormatter(feed);
            }

            private SyndicationItem GetSyndicationItemFrom(Customer customer)
            {
                UriTemplateMatch match = WebOperationContext.Current.IncomingRequest.UriTemplateMatch;
                UriTemplate template = new UriTemplate("customer/{id}");

                SyndicationItem item = new SyndicationItem()
                {
                    Id = template.BindByPosition(match.BaseUri, customer.Id).ToString(),
                    LastUpdatedTime = DateTimeOffset.Now,
                    Content = SyndicationContent.CreateXmlContent(customer)
                };
                SyndicationLink link = new SyndicationLink()
                {
                    Uri = template.BindByPosition(match.BaseUri, customer.Id),
                    RelationshipType = "edit",
                    Title = "Customers"
                };
                item.Links.Add(link);

                return item;
            }
        }

        private static readonly Uri HostBaseUri = new Uri("http://localhost:8000");
        private static readonly Uri ClientBaseUri = new Uri("http://localhost:8000");
        private WebServiceHost host_;

        [TestInitialize]
        public void サービスホスティングの開始()
        {
            host_ = new WebServiceHost(typeof(Customers), HostBaseUri);
            host_.Open();
        }

        [TestCleanup]
        public void サービスホスティングの終了()
        {
            if (host_.State != CommunicationState.Closed)
                host_.Close();
        }

        [TestMethod]
        public void Atom形式で取得したフィードからCustomerの一覧を取得できるべき()
        {
            UriTemplate template = new UriTemplate("customers?format={format}");
            XmlReader reader = XmlReader.Create(template.BindByPosition(ClientBaseUri, "atom").ToString());
            SyndicationFeed feed = SyndicationFeed.Load(reader);

            Assert.AreEqual<string>("Customers", feed.Title.Text);
            Assert.AreEqual<string>("http://localhost:8000/customers", feed.Id);
            Assert.AreEqual<int>(1, feed.Links.Count);
            Assert.AreEqual<Uri>(new Uri("http://localhost:8000/customers"), feed.Links[0].Uri);
            Assert.AreEqual<string>("self", feed.Links[0].RelationshipType);
            Assert.AreEqual<string>("Customers", feed.Links[0].Title);
            Assert.AreEqual<int>(3, feed.Items.Count());

            XmlSyndicationContent aliceContent = feed.Items.ElementAt(0).Content as XmlSyndicationContent;
            Customer alice = aliceContent.ReadContent<Customer>();
            Assert.AreEqual<string>("1, Alice, 123 Pike Place", alice.ToString());

            XmlSyndicationContent bobContent = feed.Items.ElementAt(1).Content as XmlSyndicationContent;
            Customer bob = bobContent.ReadContent<Customer>();
            Assert.AreEqual<string>("2, Bob, 12323 Lake Shore Drive", bob.ToString());

            XmlSyndicationContent johnContent = feed.Items.ElementAt(2).Content as XmlSyndicationContent;
            Customer john = johnContent.ReadContent<Customer>();
            Assert.AreEqual<string>("3, John, 4545 Wacker Drive", john.ToString());
        }

        [TestMethod]
        public void RSS形式で取得したフィードからCustomerの一覧を取得できるべき()
        {
            UriTemplate template = new UriTemplate("customers?format={format}");
            XmlReader reader = XmlReader.Create(template.BindByPosition(ClientBaseUri, "rss").ToString());
            SyndicationFeed feed = SyndicationFeed.Load(reader);

            Assert.AreEqual<string>("Customers", feed.Title.Text);
            Assert.AreEqual<string>("http://localhost:8000/customers", feed.Id);
            Assert.AreEqual<int>(1, feed.Links.Count);
            Assert.AreEqual<Uri>(new Uri("http://localhost:8000/customers"), feed.Links[0].Uri);
            Assert.AreEqual<string>("self", feed.Links[0].RelationshipType);
            Assert.AreEqual<string>("Customers", feed.Links[0].Title);
            Assert.AreEqual<int>(3, feed.Items.Count());

            XmlSyndicationContent aliceContent = feed.Items.ElementAt(0).Content as XmlSyndicationContent;
            Customer alice = aliceContent.ReadContent<Customer>();
            Assert.AreEqual<string>("1, Alice, 123 Pike Place", alice.ToString());

            XmlSyndicationContent bobContent = feed.Items.ElementAt(1).Content as XmlSyndicationContent;
            Customer bob = bobContent.ReadContent<Customer>();
            Assert.AreEqual<string>("2, Bob, 12323 Lake Shore Drive", bob.ToString());

            XmlSyndicationContent johnContent = feed.Items.ElementAt(2).Content as XmlSyndicationContent;
            Customer john = johnContent.ReadContent<Customer>();
            Assert.AreEqual<string>("3, John, 4545 Wacker Drive", john.ToString());
        }

        [TestMethod]
        public void Atom形式で取得したフィードからCustomerを取得できるべき()
        {
            UriTemplate template = new UriTemplate("customers/1?format={format}");
            XmlReader reader = XmlReader.Create(template.BindByPosition(ClientBaseUri, "atom").ToString());
            SyndicationFeed feed = SyndicationFeed.Load(reader);

            Assert.AreEqual<string>("Customers", feed.Title.Text);
            Assert.AreEqual<string>("http://localhost:8000/customers", feed.Id);
            Assert.AreEqual<int>(1, feed.Links.Count);
            Assert.AreEqual<Uri>(new Uri("http://localhost:8000/customers"), feed.Links[0].Uri);
            Assert.AreEqual<string>("self", feed.Links[0].RelationshipType);
            Assert.AreEqual<string>("Customers", feed.Links[0].Title);
            Assert.AreEqual<int>(1, feed.Items.Count());

            XmlSyndicationContent aliceContent = feed.Items.First().Content as XmlSyndicationContent;
            Customer alice = aliceContent.ReadContent<Customer>();
            Assert.AreEqual<string>("1, Alice, 123 Pike Place", alice.ToString());
        }

        [TestMethod]
        public void RSS形式で取得したフィードからCustomerを取得できるべき()
        {
            UriTemplate template = new UriTemplate("customers/1?format={format}");
            XmlReader reader = XmlReader.Create(template.BindByPosition(ClientBaseUri, "rss").ToString());
            SyndicationFeed feed = SyndicationFeed.Load(reader);

            Assert.AreEqual<string>("Customers", feed.Title.Text);
            Assert.AreEqual<string>("http://localhost:8000/customers", feed.Id);
            Assert.AreEqual<int>(1, feed.Links.Count);
            Assert.AreEqual<Uri>(new Uri("http://localhost:8000/customers"), feed.Links[0].Uri);
            Assert.AreEqual<string>("self", feed.Links[0].RelationshipType);
            Assert.AreEqual<string>("Customers", feed.Links[0].Title);
            Assert.AreEqual<int>(1, feed.Items.Count());

            XmlSyndicationContent aliceContent = feed.Items.First().Content as XmlSyndicationContent;
            Customer alice = aliceContent.ReadContent<Customer>();
            Assert.AreEqual<string>("1, Alice, 123 Pike Place", alice.ToString());
        }
    }
}

最初のテストで出力されるAtom

<feed xmlns="http://www.w3.org/2005/Atom">
   <title type="text">Customers</title>
   <id>http://localhost:8000/customers</id>
   <updated>2008-02-03T02:52:12+09:00</updated>
   <link rel="self" title="Customers" href="http://localhost:8000/customers"/>
   <entry>
      <id>http://localhost:8000/customer/1</id>
      <title type="text"/>
      <updated>2008-02-03T02:52:12+09:00</updated>
      <link rel="edit" title="Customers" href="http://localhost:8000/customer/1"/>
      <content type="text/xml">
         <SyndicationFeedTest.Customer xmlns="http://schemas.datacontract.org/2004/07/LearningWCFTests" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
            <Address>123 Pike Place</Address>
            <Id>1</Id>
            <Name>Alice</Name>
         </SyndicationFeedTest.Customer>
      </content>
   </entry>
   <entry>
      <id>http://localhost:8000/customer/2</id>
      <title type="text"/>
      <updated>2008-02-03T02:52:12+09:00</updated>
      <link rel="edit" title="Customers" href="http://localhost:8000/customer/2"/>
      <content type="text/xml">
         <SyndicationFeedTest.Customer xmlns="http://schemas.datacontract.org/2004/07/LearningWCFTests" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
            <Address>12323 Lake Shore Drive</Address>
            <Id>2</Id>
            <Name>Bob</Name>
         </SyndicationFeedTest.Customer>
      </content>
   </entry>
   <entry>
      <id>http://localhost:8000/customer/3</id>
      <title type="text"/>
      <updated>2008-02-03T02:52:12+09:00</updated>
      <link rel="edit" title="Customers" href="http://localhost:8000/customer/3"/>
      <content type="text/xml">
         <SyndicationFeedTest.Customer xmlns="http://schemas.datacontract.org/2004/07/LearningWCFTests" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
            <Address>4545 Wacker Drive</Address>
            <Id>3</Id>
            <Name>John</Name>
         </SyndicationFeedTest.Customer>
      </content>
   </entry>
</feed>

2番目のテストで出力されるRSS

<rss version="2.0" xmlns:a10="http://www.w3.org/2005/Atom">
   <channel>
      <title>Customers</title>
      <description/>
      <lastBuildDate>Sun, 03 Feb 2008 02:52:12 +0900</lastBuildDate>
      <a10:id>http://localhost:8000/customers</a10:id>
      <a10:link rel="self" title="Customers" href="http://localhost:8000/customers"/>
      <item>
         <guid isPermaLink="false">http://localhost:8000/customer/1</guid>
         <description/>
         <a10:link rel="edit" title="Customers" href="http://localhost:8000/customer/1"/>
         <a10:updated>2008-02-03T02:52:12+09:00</a10:updated>
         <a10:content type="text/xml">
            <SyndicationFeedTest.Customer xmlns="http://schemas.datacontract.org/2004/07/LearningWCFTests" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
               <Address>123 Pike Place</Address>
               <Id>1</Id>
               <Name>Alice</Name>
            </SyndicationFeedTest.Customer>
         </a10:content>
      </item>
      <item>
         <guid isPermaLink="false">http://localhost:8000/customer/2</guid>
         <description/>
         <a10:link rel="edit" title="Customers" href="http://localhost:8000/customer/2"/>
         <a10:updated>2008-02-03T02:52:12+09:00</a10:updated>
         <a10:content type="text/xml">
            <SyndicationFeedTest.Customer xmlns="http://schemas.datacontract.org/2004/07/LearningWCFTests" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
               <Address>12323 Lake Shore Drive</Address>
               <Id>2</Id>
               <Name>Bob</Name>
            </SyndicationFeedTest.Customer>
         </a10:content>
      </item>
      <item>
         <guid isPermaLink="false">http://localhost:8000/customer/3</guid>
         <description/>
         <a10:link rel="edit" title="Customers" href="http://localhost:8000/customer/3"/>
         <a10:updated>2008-02-03T02:52:12+09:00</a10:updated>
         <a10:content type="text/xml">
            <SyndicationFeedTest.Customer xmlns="http://schemas.datacontract.org/2004/07/LearningWCFTests" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
               <Address>4545 Wacker Drive</Address>
               <Id>3</Id>
               <Name>John</Name>
            </SyndicationFeedTest.Customer>
         </a10:content>
      </item>
   </channel>
</rss>