厳密に型指定された拡張のサンプル
StronglyTypedExtensions のサンプルでは、例を示す目的で SyndicationFeed クラスを使用します。 ただし、このサンプルで示すパターンは、拡張データをサポートするすべての配信クラスで使用できます。
配信オブジェクト モデル (SyndicationFeed、SyndicationItem、および関連クラス) は、AttributeExtensions プロパティおよび ElementExtensions プロパティを使用することにより、拡張データへの弱い型定義によるアクセスをサポートします。 このサンプルでは、特定のアプリケーション固有の拡張を厳密に型指定されたプロパティとして使用できるようにする SyndicationFeed および SyndicationItem のカスタム派生クラスを実装することで、拡張データへの厳密に型指定されたアクセスを提供する方法を示します。
例として、このサンプルでは Atom Threading Extensions の RFC 案で定義された拡張要素を実装する方法を示しています。 このサンプルは、使い方を示すために用意されたものであり、仕様案を完全に実装するためのものではありません。
サンプル XML
次の XML の例は、<in-reply-to>
拡張要素が追加された Atom 1.0 エントリを示しています。
<entry>
<id>tag:example.org,2005:1,2</id>
<title type="text">Another response to the original</title>
<summary type="text">
This is a response to the original entry</summary>
<updated>2006-03-01T12:12:13Z</updated>
<link href="http://www.example.org/entries/1/2" />
<in-reply-to p3:ref="tag:example.org,2005:1"
p3:href="http://www.example.org/entries/1"
p3:type="application/xhtml+xml"
xmlns:p3="http://contoso.org/syndication/thread/1.0"
xmlns="http://contoso.org/syndication/thread/1.0">
<anotherElement xmlns="http://www.w3.org/2005/Atom">
Some more data</anotherElement>
<aDifferentElement xmlns="http://www.w3.org/2005/Atom">
Even more data</aDifferentElement>
</in-reply-to>
</entry>
<in-reply-to>
要素には、3 つの必須属性 (ref
、type
、href
) を指定しますが、拡張属性や拡張要素を含めることもできます。
In-Reply-To 要素のモデル化
このサンプルでは、<in-reply-to>
要素は IXmlSerializable を実装する CLR としてモデル化されており、DataContractSerializer と共に使用できます。 さらに、次のサンプル コードに示すように、要素のデータにアクセスするためのメソッドとプロパティも実装しています。
[XmlRoot(ElementName = "in-reply-to", Namespace = "http://contoso.org/syndication/thread/1.0")]
public class InReplyToElement : IXmlSerializable
{
internal const string ElementName = "in-reply-to";
internal const string NsUri =
"http://contoso.org/syndication/thread/1.0";
private Dictionary<XmlQualifiedName, string> extensionAttributes;
private Collection<XElement> extensionElements;
public InReplyToElement()
{
this.extensionElements = new Collection<XElement>();
this.extensionAttributes = new Dictionary<XmlQualifiedName,
string>();
}
public Dictionary<XmlQualifiedName, string> AttributeExtensions
{
get { return this.extensionAttributes; }
}
public Collection<XElement> ElementExtensions
{
get { return this.extensionElements; }
}
public Uri Href
{ get; set; }
public string MediaType
{ get; set; }
public string Ref
{ get; set; }
public Uri Source
{ get; set; }
}
InReplyToElement
クラスは、必須の属性 (HRef
、MediaType
、および Source
) のプロパティと共に、AttributeExtensions および ElementExtensions を保持するコレクションを実装します。
InReplyToElement
クラスは、IXmlSerializable インターフェイスを実装します。このインターフェイスは、オブジェクト インスタンスを XML から読み取る、または書き込む方法の直接制御を可能にします。 ReadXml
メソッドは、渡された Ref
から HRef
、Source
、MediaType
、および XmlReader の各プロパティを最初に読み取ります。 不明な属性はAttributeExtensions コレクションに格納されます。 すべての属性が読み取られると、ReadStartElement() が呼び出されて、リーダーが次の要素に進みます。 次のコードに示すように、このクラスによりモデル化された要素には必須の子がないので、子要素は XElement
インスタンスにバッファされ、ElementExtensions コレクションに格納されます。
public void ReadXml(System.Xml.XmlReader reader)
{
bool isEmpty = reader.IsEmptyElement;
if (reader.HasAttributes)
{
for (int i = 0; i < reader.AttributeCount; i++)
{
reader.MoveToNextAttribute();
if (reader.NamespaceURI == "")
{
if (reader.LocalName == "ref")
{
this.Ref = reader.Value;
}
else if (reader.LocalName == "href")
{
this.Href = new Uri(reader.Value);
}
else if (reader.LocalName == "source")
{
this.Source = new Uri(reader.Value);
}
else if (reader.LocalName == "type")
{
this.MediaType = reader.Value;
}
else
{
this.AttributeExtensions.Add(new
XmlQualifiedName(reader.LocalName,
reader.NamespaceURI),
reader.Value);
}
}
}
}
reader.ReadStartElement();
if (!isEmpty)
{
while (reader.IsStartElement())
{
ElementExtensions.Add(
(XElement) XElement.ReadFrom(reader));
}
reader.ReadEndElement();
}
}
WriteXml
では、InReplyToElement
メソッドは最初に Ref
、HRef
、Source
、および MediaType
の各プロパティの値を XML 属性として書き込みます (WriteXml
は、実際の外側の要素自体は書き込みません。WriteXml
により行われるためです)。 また、次のコードに示すように、AttributeExtensions および ElementExtensions の内容をライタに書き込みます。
public void WriteXml(System.Xml.XmlWriter writer)
{
if (this.Ref != null)
{
writer.WriteAttributeString("ref", InReplyToElement.NsUri,
this.Ref);
}
if (this.Href != null)
{
writer.WriteAttributeString("href", InReplyToElement.NsUri,
this.Href.ToString());
}
if (this.Source != null)
{
writer.WriteAttributeString("source", InReplyToElement.NsUri,
this.Source.ToString());
}
if (this.MediaType != null)
{
writer.WriteAttributeString("type", InReplyToElement.NsUri,
this.MediaType);
}
foreach (KeyValuePair<XmlQualifiedName, string> kvp in
this.AttributeExtensions)
{
writer.WriteAttributeString(kvp.Key.Name, kvp.Key.Namespace,
kvp.Value);
}
foreach (XElement element in this.ElementExtensions)
{
element.WriteTo(writer);
}
}
ThreadedFeed および ThreadedItem
このサンプルでは、SyndicationItems
拡張が存在する InReplyTo
が ThreadedItem
クラスによりモデル化されます。 同様に、ThreadedFeed
クラスは、項目が SyndicationFeed
のすべてのインスタンスである ThreadedItem
です。
ThreadedFeed
クラスは、SyndicationFeed
から継承され、OnCreateItem
をオーバーライドして ThreadedItem
を返します。 また、次のコードに示すように、Items
コレクションにアクセスするメソッドを ThreadedItems
として実装します。
public class ThreadedFeed : SyndicationFeed
{
public ThreadedFeed()
{
}
public IEnumerable<ThreadedItem> ThreadedItems
{
get
{
return this.Items.Cast<ThreadedItem>();
}
}
protected override SyndicationItem CreateItem()
{
return new ThreadedItem();
}
}
ThreadedItem
クラスは SyndicationItem
から継承され、InReplyToElement
を厳密に型指定されたプロパティにします。 これにより、InReplyTo
拡張データにプログラムによって簡単にアクセスできます。 また、次のコードに示すように、その拡張データの読み取り/書き込みを行う TryParseElement
および WriteElementExtensions
も実装します。
public class ThreadedItem : SyndicationItem
{
private InReplyToElement inReplyTo;
// Constructors
public ThreadedItem()
{
inReplyTo = new InReplyToElement();
}
public ThreadedItem(string title, string content, Uri itemAlternateLink, string id, DateTimeOffset lastUpdatedTime) : base(title, content, itemAlternateLink, id, lastUpdatedTime)
{
inReplyTo = new InReplyToElement();
}
public InReplyToElement InReplyTo
{
get { return this.inReplyTo; }
}
protected override bool TryParseElement(
System.Xml.XmlReader reader,
string version)
{
if (version == SyndicationVersions.Atom10 &&
reader.NamespaceURI == InReplyToElement.NsUri &&
reader.LocalName == InReplyToElement.ElementName)
{
this.inReplyTo = new InReplyToElement();
this.InReplyTo.ReadXml(reader);
return true;
}
else
{
return base.TryParseElement(reader, version);
}
}
protected override void WriteElementExtensions(XmlWriter writer,
string version)
{
if (this.InReplyTo != null &&
version == SyndicationVersions.Atom10)
{
writer.WriteStartElement(InReplyToElement.ElementName,
InReplyToElement.NsUri);
this.InReplyTo.WriteXml(writer);
writer.WriteEndElement();
}
base.WriteElementExtensions(writer, version);
}
}
サンプルをセットアップ、ビルド、および実行するには
Windows Communication Foundation サンプルの 1 回限りのセットアップの手順を実行したことを確認します。
ソリューションの C# 版または Visual Basic .NET 版をビルドするには、「 Building the Windows Communication Foundation Samples」の手順に従います。
単一または複数コンピューター構成でサンプルを実行するには、「Windows Communication Foundation サンプルの実行」の手順に従います。