Bagikan melalui


Sampel ekstensi strongly-typed

Sampel StronglyTypedExtensions menggunakan kelas SyndicationFeed untuk tujuan contoh. Namun, pola yang ditunjukkan dalam sampel ini dapat digunakan dengan semua kelas Sindikasi yang mendukung data ekstensi.

Model objek Sindikasi (SyndicationFeed, SyndicationItem, dan kelas terkait) menunjukkan akses loosely-typed ke data ekstensi menggunakan properti AttributeExtensions dan ElementExtensions. Sampel ini menunjukkan cara memberikan akses strongly-typed ke data ekstensi dengan mengimplementasikan kelas turunan kustom SyndicationFeed dan SyndicationItem yang menyediakan ekstensi khusus aplikasi tertentu sebagai properti strongly-typed.

Sebagai contoh, sampel ini menunjukkan cara mengimplementasikan elemen ekstensi yang ditentukan dalam RFC Ekstensi Threading Atom yang diusulkan. Ini hanya untuk tujuan demonstrasi dan sampel ini tidak dimaksudkan untuk menjadi implementasi penuh dari spesifikasi yang diusulkan.

XML Sampel

Contoh XML berikut menunjukkan entri Atom 1.0 dengan elemen ekstensi <in-reply-to> tambahan.

<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>

Elemen <in-reply-to> menentukan tiga atribut yang diperlukan (ref, type, dan href) sekaligus memungkinkan keberadaan atribut ekstensi dan elemen ekstensi tambahan.

Memodelkan elemen In-Reply-To

Dalam sampel ini, elemen <in-reply-to> dimodelkan sebagai CLR yang mengimplementasikan IXmlSerializable, yang memungkinkan penggunaannya dengan DataContractSerializer. Hal ini juga mengimplementasikan beberapa metode dan properti untuk mengakses data elemen, seperti yang ditunjukkan dalam kode sampel berikut.

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

Kelas InReplyToElement mengimplementasikan properti untuk atribut yang diperlukan (HRef, MediaType, dan Source) serta koleksi untuk menyimpan AttributeExtensions dan ElementExtensions.

Kelas InReplyToElement mengimplementasikan antarmuka IXmlSerializable, yang memungkinkan kontrol langsung atas cara instans objek dibaca dari dan ditulis ke XML. Metode ReadXml terlebih dahulu membaca nilai untuk properti Ref, HRef, Source, dan MediaType dari XmlReader yang diteruskan ke dalamnya. Atribut yang tidak diketahui disimpan dalam koleksi AttributeExtensions. Setelah semua atribut dibaca, ReadStartElement() dipanggil untuk mendorong pembaca ke elemen berikutnya. Karena elemen yang dimodelkan oleh kelas ini tidak memiliki turunan yang diperlukan, elemen turunan di-buffer ke dalam instans XElement dan disimpan dalam koleksi ElementExtensions, seperti yang ditampilkan dalam kode berikut.

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

Dalam WriteXml, metode InReplyToElement terlebih dahulu menulis nilai untuk properti Ref, HRef, Source, dan MediaType sebagai atribut XML (WriteXml tidak bertanggung jawab untuk menulis elemen luar yang aktual sendiri, seperti yang dilakukan oleh pemanggil WriteXml). Metode ini juga menulis konten AttributeExtensions dan ElementExtensions ke penulis, seperti yang ditampilkan dalam kode berikut.

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 dan ThreadedItem

Pada sampel, SyndicationItems dengan InReplyTo ekstensi dimodelkan oleh kelas ThreadedItem. Demikian pula, kelas ThreadedFeed adalah SyndicationFeed yang itemnya merupakan semua instans dari ThreadedItem.

Kelas ThreadedFeed mewarisi dari SyndicationFeed dan mengambil alih OnCreateItem untuk mengembalikan ThreadedItem. Hal ini juga mengimplementasikan metode untuk mengakses koleksi Items sebagai ThreadedItems, seperti yang ditunjukkan pada kode berikut.

public class ThreadedFeed : SyndicationFeed
{
    public ThreadedFeed()
    {
    }

    public IEnumerable<ThreadedItem> ThreadedItems
    {
        get
        {
            return this.Items.Cast<ThreadedItem>();
        }
    }

    protected override SyndicationItem CreateItem()
    {
        return new ThreadedItem();
    }
}

Kelas ThreadedItem mewarisi dari SyndicationItem dan menjadikan InReplyToElement sebagai properti strongly-typed. Ini menyediakan akses terprogram yang mudah ke data ekstensi InReplyTo. Hal tersebut juga mengimplementasikan TryParseElement dan WriteElementExtensions untuk membaca dan menulis data ekstensinya, seperti yang ditunjukkan pada kode berikut.

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

Untuk menyiapkan, membangun, dan menjalankan sampel

  1. Pastikan Anda telah melakukan Prosedur Penyiapan Satu Kali untuk Sampel Windows Communication Foundation.

  2. Untuk membangun solusi edisi C# atau Visual Basic .NET, ikuti petunjuknya di Membangun Sampel WCF.

  3. Untuk menjalankan sampel dalam konfigurasi satu atau lintas komputer, ikuti instruksi pada Menjalankan Sampel WCF.