Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
O exemplo StronglyTypedExtensions usa a SyndicationFeed classe para fins do exemplo. No entanto, os padrões demonstrados nesta amostra podem ser usados com todas as classes de Syndication que dão suporte a dados de extensão.
O modelo de objeto Syndication (SyndicationFeed, SyndicationItem e classes relacionadas) dá suporte ao acesso de tipo flexível aos dados de extensão usando as propriedades AttributeExtensions e ElementExtensions. Este exemplo mostra como fornecer acesso fortemente tipado aos dados de extensão implementando classes derivadas personalizadas de SyndicationFeed e SyndicationItem que disponibilizam determinadas extensões específicas do aplicativo como propriedades fortemente tipadas.
Como uma demonstração, este exemplo mostra como implementar um elemento de extensão definido no RFC de extensões de threading Atom propostas. Isso é 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 elemento <in-reply-to> 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; }
}
InReplyToElement a classe implementa propriedades para o atributo necessário (HRef, MediaType e Source), bem como coleções para armazenar 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 propriedades Ref, HRef, Source e MediaType do XmlReader passado para ele. Todos os atributos desconhecidos são armazenados na AttributeExtensions coleção. Quando todos os atributos foram lidos, ReadStartElement() é chamado para avançar o leitor para o próximo elemento. Como o elemento modelado por esta classe não tem filhos necessários, os elementos filho são armazenados em instâncias XElement e armazenados na coleção ElementExtensions, 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();
}
}
In WriteXml, o método InReplyToElement primeiro grava os valores das propriedades Ref, HRef, Source e MediaType como atributos XML (WriteXml não é responsável por escrever o elemento externo real em si, pois isso é feito pelo chamador de WriteXml). Ele também grava o conteúdo de AttributeExtensions e ElementExtensions no gravador, conforme 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 é um SyndicationFeed cujos itens são todas instâncias de ThreadedItem.
A classe ThreadedFeed herda de SyndicationFeed e substitui OnCreateItem para retornar um ThreadedItem. 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 de InReplyToElement uma propriedade fortemente tipada. Isso fornece acesso programático conveniente aos dados de extensão de InReplyTo. Ele também implementa TryParseElement e WriteElementExtensions para ler e gravar seus dados de extensão, conforme 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
Verifique se você executou o Procedimento de instalação avulsa dos exemplos do Windows Communication Foundation.
Para compilar a edição .NET do C# ou do Visual Basic da solução, siga as instruções contidas em Como Compilar as Amostras do Windows Communication Foundation.
Para executar o exemplo em uma configuração única ou entre máquinas, siga as instruções em Executando os exemplos do Windows Communication Foundation.