Compartir a través de


Ejemplo de extensiones fuertemente tipadas

El ejemplo StronglyTypedExtensions usa la SyndicationFeed clase para los fines del ejemplo. Sin embargo, los patrones que se muestran en este ejemplo se pueden usar con todas las clases de syndication que admiten datos de extensión.

El modelo de objetos de sindicación (SyndicationFeed, SyndicationItem, y clases relacionadas) admite el acceso poco estrictamente tipificado a los datos de extensión mediante las propiedades AttributeExtensions y ElementExtensions. En este ejemplo se muestra cómo proporcionar acceso fuertemente tipado a los datos de extensión mediante la implementación de clases derivadas personalizadas de SyndicationFeed y SyndicationItem, que hacen que ciertas extensiones específicas de la aplicación estén disponibles como propiedades fuertemente tipadas.

Como ejemplo, este ejemplo muestra cómo implementar un elemento de extensión definido en el RFC de las extensiones de subprocesamiento de Atom propuesto. Esto solo tiene fines de demostración y este ejemplo no está pensado para ser una implementación completa de la especificación propuesta.

XML de ejemplo

En el ejemplo XML siguiente se muestra una entrada atom 1.0 con un elemento de extensión adicional <in-reply-to> .

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

El <in-reply-to> elemento especifica tres atributos necesarios (ref, type y href) al mismo tiempo que permite la presencia de atributos de extensión y elementos de extensión adicionales.

Modelado del elemento In-Reply-To

En este ejemplo, el elemento <in-reply-to> se modela como un CLR que implementa IXmlSerializable, lo que permite su uso con el DataContractSerializer. También implementa algunos métodos y propiedades para acceder a los datos del elemento, como se muestra en el código de ejemplo siguiente.

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

La InReplyToElement clase implementa propiedades para el atributo necesario (HRef, MediaTypey Source) así como colecciones que contienen AttributeExtensions y ElementExtensions.

La InReplyToElement clase implementa la IXmlSerializable interfaz , que permite el control directo sobre cómo se leen y escriben las instancias de objeto en XML. El método ReadXml lee primero los valores de las propiedades Ref, HRef, Source y MediaType del objeto XmlReader pasado a él. Los atributos desconocidos se almacenan en la AttributeExtensions colección. Cuando se han leído todos los atributos, ReadStartElement() se llama para avanzar al lector al siguiente elemento. Dado que el elemento modelado por esta clase no tiene elementos secundarios necesarios, los elementos secundarios se almacenan en búfer en XElement instancias y se almacenan en la ElementExtensions colección, como se muestra en el código siguiente.

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

En WriteXml, el método InReplyToElement escribe primero los valores de las propiedades Ref, HRef, Source y MediaType como atributos XML (WriteXml no es responsable de escribir el propio elemento externo real, ya que eso lo realiza quien llama a WriteXml). También escribe el contenido de AttributeExtensions y ElementExtensions en el sistema de escritura, como se muestra en el código siguiente.

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

En el ejemplo, SyndicationItems con InReplyTo extensiones se modelan mediante la clase ThreadedItem. Del mismo modo, la ThreadedFeed clase es un SyndicationFeed cuyos elementos son todas las instancias de ThreadedItem.

La ThreadedFeed clase hereda de SyndicationFeed e invalida OnCreateItem para devolver un ThreadedItem. También implementa un método para acceder a la Items colección como ThreadedItems, como se muestra en el código siguiente.

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

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

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

La clase ThreadedItem hereda de SyndicationItem y hace de InReplyToElement una propiedad fuertemente tipada. Esto proporciona un acceso programático conveniente a los datos de la extensión InReplyTo. También implementa TryParseElement y WriteElementExtensions para leer y escribir sus datos de extensión, como se muestra en el código siguiente.

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

Para configurar, compilar y ejecutar el ejemplo

  1. Asegúrese de que ha realizado el procedimiento de instalación única para los ejemplos de Windows Communication Foundation.

  2. Para compilar el código C# o Visual Basic .NET Edition de la solución, siga las instrucciones de Building the Windows Communication Foundation Samples.

  3. Para ejecutar el ejemplo en una configuración de una máquina única o entre máquinas, siga las instrucciones de Ejecución de los ejemplos de Windows Communication Foundation.