强类型扩展示例
StronglyTypedExtensions 示例使用 SyndicationFeed 类作为示例。 但是,此示例中演示的模式可用于支持扩展数据的所有 Syndication 类。
联合对象模型(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>
元素指定三个必需的属性(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
类实现所需属性 (Attribute) 的属性 (Property)(HRef
、MediaType
和 Source
)以及用于保存 AttributeExtensions 和 ElementExtensions 的集合。
InReplyToElement
类实现 IXmlSerializable 接口,该接口允许直接控制从 XML 读取对象实例和向 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);
}
}
设置、生成和运行示例
若要生成 C# 或 Visual Basic .NET 版本的解决方案,请按照 Building the Windows Communication Foundation Samples中的说明进行操作。
要使用单机配置或跨计算机配置来运行示例,请按照运行 Windows Communication Foundation 示例中的说明进行操作。