Partilhar via


Exemplo de extensões fortemente tipadas

O exemplo StronglyTypedExtensions usa a SyndicationFeed classe para os fins do exemplo. No entanto, os padrões demonstrados neste exemplo podem ser usados com todas as classes Syndication que suportam dados de extensão.

O modelo de objeto Syndication (SyndicationFeed, SyndicationIteme classes relacionadas) oferece suporte a acesso de tipo flexível a dados de extensão usando as AttributeExtensions propriedades e ElementExtensions . Este exemplo mostra como fornecer acesso fortemente tipado a dados de extensão implementando classes derivadas personalizadas de e SyndicationItem que disponibilizam determinadas extensões específicas do SyndicationFeed aplicativo como propriedades fortemente tipadas.

Como exemplo, este exemplo mostra como implementar um elemento de extensão definido na proposta Atom Threading Extensions RFC. Isto é apenas para fins de demonstração e este exemplo não se destina a ser uma implementação completa da especificação proposta.

XML de exemplo

O exemplo XML a seguir mostra uma entrada Atom 1.0 com um elemento de extensão 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>

O <in-reply-to> elemento especifica três atributos necessários (ref, type e href), ao mesmo tempo em que permite a presença de atributos de extensão adicionais e elementos de extensão.

Modelando o elemento In-Reply-To

Neste exemplo, o <in-reply-to> elemento é modelado como CLR que implementa IXmlSerializable, o que permite seu uso com o DataContractSerializer. Ele também implementa alguns métodos e propriedades para acessar os dados do elemento, conforme mostrado no código de exemplo a seguir.

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

A InReplyToElement classe implementa propriedades para o atributo necessário (HRef, MediaTypee Source), bem como coleções para manter AttributeExtensions e ElementExtensions.

A InReplyToElement classe implementa a IXmlSerializable interface, que permite controle direto sobre como as instâncias de objeto são lidas e gravadas em XML. O ReadXml método primeiro lê os valores para as Refpropriedades , HRef, Sourcee MediaType do XmlReader passado para ele. Todos os atributos desconhecidos são armazenados na AttributeExtensions coleção. Quando todos os atributos tiverem sido lidos, ReadStartElement() é chamado para avançar o leitor para o próximo elemento. Como o elemento modelado por essa classe não tem filhos necessários, os elementos filho são armazenados em buffer em XElement instâncias e armazenados na ElementExtensions coleção, conforme mostrado no código a seguir.

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

No WriteXml, o InReplyToElement método primeiro grava os valores das Refpropriedades , HRef, Source, e MediaType como atributos XML (WriteXml não é responsável por escrever o elemento externo em si, como o feito pelo chamador de WriteXml). Ele também escreve o conteúdo do AttributeExtensions e ElementExtensions para o escritor, como mostrado no código a seguir.

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

No exemplo, SyndicationItems com InReplyTo extensões são modeladas pela ThreadedItem classe. Da mesma forma, a ThreadedFeed classe é uma SyndicationFeed cujos itens são todas as instâncias de ThreadedItem.

A ThreadedFeed classe herda e SyndicationFeed substitui OnCreateItem para retornar um ThreadedItemarquivo . Ele também implementa um método para acessar a Items coleção como ThreadedItems, conforme mostrado no código a seguir.

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

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

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

A classe ThreadedItem herda de SyndicationItem e faz InReplyToElement como uma propriedade fortemente tipada. Isso fornece acesso programático conveniente aos dados de InReplyTo extensão. Ele também implementa e WriteElementExtensions para ler e escrever seus dados de TryParseElement extensão, como mostrado no código a seguir.

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 e executar o exemplo

  1. Certifique-se de ter executado o procedimento de instalação única para os exemplos do Windows Communication Foundation.

  2. Para criar a edição C# ou Visual Basic .NET da solução, siga as instruções em Criando os exemplos do Windows Communication Foundation.

  3. Para executar o exemplo em uma configuração de máquina única ou cruzada, siga as instruções em Executando os exemplos do Windows Communication Foundation.