共用方式為


強型別延伸模組範例

基於示範用途,StronglyTypedExtensions 範例會使用 SyndicationFeed 類別。 不過在此範例中所示範的模式,可以與所有支援延伸資料的新聞訂閱類別一起使用。

Syndication 物件模型 (SyndicationFeedSyndicationItem 和相關類別) 會使用 AttributeExtensionsElementExtensions 屬性,藉此支援對延伸資料的鬆散型別存取。 此範例說明如何實作 SyndicationFeedSyndicationItem 的自訂衍生型別,以便使用某些特定應用程式延伸模組作為強型別屬性,藉此提供對延伸模組資料的強型別存取。

例如,此範例說明如何實作在建議的 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> 元素會指定三個必要的屬性 (reftypehref),同時也允許其他延伸模組屬性和延伸模組元素存在。

建立 In-Reply-To 項目的模型

在本範例中,<in-reply-to> 項目會模型化為實作 IXmlSerializable 以便與 DataContractSerializer 搭配使用的 CLR。 此外,也會實作用於存取元素資料的方法和屬性,如下列範例程式碼所示。

[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) (HRefMediaTypeSource) 以及集合實作屬性 (Property),以保存 AttributeExtensionsElementExtensions

InReplyToElement 類別會實作 IXmlSerializable 介面,這個介面允許直接控制要以何種方式從 XML 讀取物件執行個體,以及將物件執行個體寫入至 XML。 ReadXml 方法會先從傳遞給它的 Ref 讀取 HRefSourceMediaType 以及 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 方法會先寫出 RefHRefSourceMediaType 屬性 (Property) 的值做為 XML 屬性 (Attribute) (WriteXml 不負責自己寫入實際外部項目,因為這項作業是由 WriteXml 的呼叫者來完成)。 此外,它也會將 AttributeExtensionsElementExtensions 的內容寫入至寫入器,如下列程式碼所示。

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 延伸資料。 它也會實作 TryParseElementWriteElementExtensions 以便讀取和寫入其延伸資料,如下列程式碼所示。

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);
    }
}

若要安裝、建置及執行範例

  1. 確定您已執行 Windows Communication Foundation 範例的一次性安裝程序

  2. 若要建置方案的 C# 或 Visual Basic .NET 版本,請遵循 Building the Windows Communication Foundation Samples中的指示。

  3. 若要在單一或多部電腦組態中執行此範例,請遵循執行 Windows Communication Foundation 範例中的指示進行。