WCF Webプログラミングモデルの学習テスト Part4
先日のWCF 配信の学習テストを変更。AtomフィードとRSSフィードを使用した POST / GET / PUT / DELETE について。
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(Atom10ItemFormatter))] [ServiceKnownType(typeof(Rss20ItemFormatter))] SyndicationItemFormatter GetCustomer(string id, string format); [OperationContract] [WebInvoke(Method = "POST", UriTemplate = "customers?format={format}")] [ServiceKnownType(typeof(Atom10ItemFormatter))] [ServiceKnownType(typeof(Rss20ItemFormatter))] SyndicationItemFormatter AddCustomer(SyndicationItemFormatter customerFormatter, string format); [OperationContract] [WebInvoke(Method = "PUT", UriTemplate = "customers/{id}?format={format}")] [ServiceKnownType(typeof(Atom10ItemFormatter))] [ServiceKnownType(typeof(Rss20ItemFormatter))] SyndicationItemFormatter UpdateCustomer(string id, SyndicationItemFormatter customerFormatter, string format); [OperationContract] [WebInvoke(Method = "DELETE", UriTemplate = "customers/{id}")] void DeleteCustomer(string id); } [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); } } [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public class Customers : ICustomers { private int lastId_ = 0; private List<Customer> customers_ = new List<Customer>(); private static object syncRoot_ = new Object(); public SyndicationFeedFormatter GetCustomers(string format) { return CreateFeedFormatterFrom(customers_, format); } public SyndicationItemFormatter GetCustomer(string id, string format) { if (NotContainsCustomer(id)) { // HTTP ステータス 404 WebOperationContext.Current.OutgoingResponse.SetStatusAsNotFound(); return null; } return CreateItemFormatterFrom( customers_.First(customer => customer.Id == id), format); } public SyndicationItemFormatter AddCustomer(SyndicationItemFormatter customerFormatter, string format) { SyndicationItemFormatter formatter = null; lock (syncRoot_) { XmlSyndicationContent content = customerFormatter.Item.Content as XmlSyndicationContent; Customer customer = content.ReadContent<Customer>(); lastId_++; customer.Id = lastId_.ToString(); customers_.Add(customer); formatter = CreateItemFormatterFrom(customer, format); UriTemplateMatch match = WebOperationContext.Current.IncomingRequest.UriTemplateMatch; UriTemplate template = new UriTemplate("customers/{id}"); // HTTP ステータス 201 WebOperationContext.Current.OutgoingResponse.SetStatusAsCreated( template.BindByPosition(match.BaseUri, customer.Id)); } return formatter; } public SyndicationItemFormatter UpdateCustomer(string id, SyndicationItemFormatter customerFormatter, string format) { SyndicationItemFormatter formatter = null; if (NotContainsCustomer(id)) { // HTTP ステータス 404 WebOperationContext.Current.OutgoingResponse.SetStatusAsNotFound(); return null; } lock (syncRoot_) { XmlSyndicationContent content = customerFormatter.Item.Content as XmlSyndicationContent; customers_.Remove(customers_.Single(customer => customer.Id == id)); Customer updatedCustomer = content.ReadContent<Customer>(); customers_.Add(updatedCustomer); formatter = CreateItemFormatterFrom(updatedCustomer, format); } return formatter; } public void DeleteCustomer(string id) { if (NotContainsCustomer(id)) { // HTTP ステータス 404 WebOperationContext.Current.OutgoingResponse.SetStatusAsNotFound(); return; } lock (syncRoot_) { customers_.Remove(customers_.Single(customer => customer.Id == id)); } } private SyndicationFeedFormatter CreateFeedFormatterFrom(IEnumerable<Customer> customers, string format) { UriTemplateMatch match = WebOperationContext.Current.IncomingRequest.UriTemplateMatch; UriTemplate template = new UriTemplate("customers"); SyndicationFeed feed = new SyndicationFeed() { 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 SyndicationItemFormatter CreateItemFormatterFrom(Customer customer, string format) { if (format == "atom") return new Atom10ItemFormatter(GetSyndicationItemFrom(customer)); else return new Rss20ItemFormatter(GetSyndicationItemFrom(customer)); } private SyndicationItem GetSyndicationItemFrom(Customer customer) { UriTemplateMatch match = WebOperationContext.Current.IncomingRequest.UriTemplateMatch; UriTemplate template = new UriTemplate("customers/{id}"); SyndicationItem item = new SyndicationItem() { Title = SyndicationContent.CreatePlaintextContent("Customer"), LastUpdatedTime = DateTimeOffset.Now, Content = SyndicationContent.CreateXmlContent(customer) }; SyndicationLink link = new SyndicationLink() { Uri = template.BindByPosition(match.BaseUri, customer.Id), RelationshipType = "edit", Title = "Customer" }; item.Links.Add(link); return item; } private bool NotContainsCustomer(string id) { return customers_.SingleOrDefault(customer => customer.Id == id) == null; } } private static readonly Uri HostingBaseUri = new Uri("http://localhost:8000"); private static readonly Uri ClientBaseUri = new Uri("http://localhost:8000"); private WebServiceHost host_; private string aliceId_; private string bobId_; [TestInitialize] public void サービスホスティングの開始とCustomerの登録() { host_ = new WebServiceHost(typeof(Customers), HostingBaseUri); host_.Open(); using (WebChannelFactory<ICustomers> cf = new WebChannelFactory<ICustomers>(ClientBaseUri)) { ICustomers channel = cf.CreateChannel(); aliceId_ = AddCustomer( new Customer() { Name = "Alice", Address = "123 Pike Place" }, channel, "atom").Id; bobId_ = AddCustomer( new Customer() { Name = "Bob", Address = "12323 Lake Shore Drive" }, channel, "atom").Id; } } private Customer AddCustomer(Customer customer, ICustomers channel, string format) { SyndicationItemFormatter formatter = channel.AddCustomer( GetItemFormatterFrom(customer, format), format); XmlSyndicationContent content = formatter.Item.Content as XmlSyndicationContent; return content.ReadContent<Customer>(); } private SyndicationItemFormatter GetItemFormatterFrom(Customer customer, string format) { SyndicationItem item = new SyndicationItem() { Title = SyndicationContent.CreatePlaintextContent("Customer"), LastUpdatedTime = DateTimeOffset.Now, Content = SyndicationContent.CreateXmlContent(customer) }; if (format == "atom") return item.GetAtom10Formatter(); else return item.GetRss20Formatter(); } [TestCleanup] public void サービスホスティングの終了() { if (host_.State != CommunicationState.Closed) host_.Close(); } [TestMethod] public void Atom形式のフィードからCustomerが追加できるべき() { Customerが追加できるべき("atom"); } [TestMethod] public void RSS形式のフィードからCustomerが追加できるべき() { Customerが追加できるべき("rss"); } private void Customerが追加できるべき(string feed) { using (WebChannelFactory<ICustomers> cf = new WebChannelFactory<ICustomers>(ClientBaseUri)) { ICustomers channel = cf.CreateChannel(); Customer john = AddCustomer( new Customer() { Name = "John", Address = "4545 Wacker Drive" }, channel, feed); Assert.AreEqual<string>(string.Format("{0}, John, 4545 Wacker Drive", john.Id), john.ToString()); SyndicationItemFormatter insertedJohnFormatter = channel.GetCustomer(john.Id, feed); XmlSyndicationContent insertedJohnContent = insertedJohnFormatter.Item.Content as XmlSyndicationContent; Assert.AreEqual<string>(string.Format("{0}, John, 4545 Wacker Drive", john.Id), insertedJohnContent.ReadContent<Customer>().ToString()); } } [TestMethod] public void Atom形式で取得したフィードからCustomerの一覧を取得できるべき() { Customerの一覧を取得できるべき("atom"); } [TestMethod] public void RSS形式で取得したフィードからCustomerの一覧を取得できるべき() { Customerの一覧を取得できるべき("rss"); } private void Customerの一覧を取得できるべき(string format) { UriTemplate template = new UriTemplate("customers?format={format}"); XmlReader reader = XmlReader.Create(template.BindByPosition(ClientBaseUri, format).ToString()); SyndicationFeed feed = SyndicationFeed.Load(reader); Assert.AreEqual<string>("Customers", feed.Title.Text); Assert.AreEqual<int>(1, feed.Links.Count); Assert.AreEqual<string>("Customers", feed.Title.Text); Assert.AreEqual<Uri>(new Uri("http://localhost:8000/customers"), feed.Links.First().Uri); Assert.AreEqual<string>("self", feed.Links.First().RelationshipType); Assert.AreEqual<string>("Customers", feed.Links.First().Title); Assert.AreEqual<int>(2, feed.Items.Count()); UriTemplate customerTemplate = new UriTemplate("customers/{id}"); Assert.AreEqual<string>("Customer", feed.Items.ElementAt(0).Title.Text); Assert.AreEqual<Uri>(customerTemplate.BindByPosition(HostingBaseUri, aliceId_), feed.Items.ElementAt(0).Links.First().Uri); Assert.AreEqual<string>("edit", feed.Items.ElementAt(0).Links.First().RelationshipType); Assert.AreEqual<string>("Customer", feed.Items.ElementAt(0).Links.First().Title); XmlSyndicationContent aliceContent = feed.Items.ElementAt(0).Content as XmlSyndicationContent; Customer alice = aliceContent.ReadContent<Customer>(); Assert.AreEqual<string>(string.Format("{0}, Alice, 123 Pike Place", aliceId_), alice.ToString()); Assert.AreEqual<string>("Customer", feed.Items.ElementAt(1).Title.Text); Assert.AreEqual<Uri>(customerTemplate.BindByPosition(HostingBaseUri, bobId_), feed.Items.ElementAt(1).Links.First().Uri); Assert.AreEqual<string>("edit", feed.Items.ElementAt(1).Links.First().RelationshipType); Assert.AreEqual<string>("Customer", feed.Items.ElementAt(1).Links.First().Title); XmlSyndicationContent bobContent = feed.Items.ElementAt(1).Content as XmlSyndicationContent; Customer bob = bobContent.ReadContent<Customer>(); Assert.AreEqual<string>(string.Format("{0}, Bob, 12323 Lake Shore Drive", bobId_), bob.ToString()); } [TestMethod] public void Atom形式で取得したフィードからCustomerを取得できるべき() { Customerを取得できるべき("atom"); } [TestMethod] public void RSS形式で取得したフィードからCustomerを取得できるべき() { Customerを取得できるべき("rss"); } private void Customerを取得できるべき(string format) { UriTemplate template = new UriTemplate("customers/{id}?format={format}"); XmlReader reader = XmlReader.Create(template.BindByPosition(ClientBaseUri, aliceId_, format).ToString()); SyndicationItem item = SyndicationItem.Load(reader); Assert.AreEqual<string>("Customer", item.Title.Text); UriTemplate customerTemplate = new UriTemplate("customers/{id}"); Assert.AreEqual<Uri>(customerTemplate.BindByPosition(HostingBaseUri, aliceId_), item.Links.First().Uri); Assert.AreEqual<string>("edit", item.Links.First().RelationshipType); Assert.AreEqual<string>("Customer", item.Links.First().Title); XmlSyndicationContent content = item.Content as XmlSyndicationContent; Customer alice = content.ReadContent<Customer>(); Assert.AreEqual<string>(string.Format("{0}, Alice, 123 Pike Place", aliceId_), alice.ToString()); } [TestMethod] public void Atom形式のフィードからCustomerが更新できるべき() { Customerが更新できるべき("atom"); } [TestMethod] public void RSS形式のフィードからCustomerが更新できるべき() { Customerが更新できるべき("rss"); } private void Customerが更新できるべき(string format) { using (WebChannelFactory<ICustomers> cf = new WebChannelFactory<ICustomers>(ClientBaseUri)) { ICustomers channel = cf.CreateChannel(); SyndicationItemFormatter aliceFormatter = channel.GetCustomer(aliceId_, format); XmlSyndicationContent aliceContent = aliceFormatter.Item.Content as XmlSyndicationContent; Customer alice = aliceContent.ReadContent<Customer>(); alice.Name = "Charlie"; XmlSyndicationContent charlieContent = channel.UpdateCustomer( aliceId_, GetItemFormatterFrom(alice, format), format).Item.Content as XmlSyndicationContent; Customer charlie = charlieContent.ReadContent<Customer>(); Assert.AreEqual<string>(string.Format("{0}, Charlie, 123 Pike Place", charlie.Id), charlie.ToString()); SyndicationItemFormatter updatedCharlieformatter = channel.GetCustomer(charlie.Id, format); XmlSyndicationContent updatedCharlieContent = updatedCharlieformatter.Item.Content as XmlSyndicationContent; Assert.AreEqual<string>(string.Format("{0}, Charlie, 123 Pike Place", charlie.Id), updatedCharlieContent.ReadContent<Customer>().ToString()); } } [TestMethod] [ExpectedException(typeof(EndpointNotFoundException))] public void Customerが削除できるべき() { using (WebChannelFactory<ICustomers> cf = new WebChannelFactory<ICustomers>(ClientBaseUri)) { ICustomers channel = cf.CreateChannel(); channel.DeleteCustomer(aliceId_); channel.GetCustomer(aliceId_, "atom"); } } } }