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
, MediaType
e 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 Ref
propriedades , HRef
, Source
e 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 Ref
propriedades , 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 ThreadedItem
arquivo . 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
Certifique-se de ter executado o procedimento de instalação única para os exemplos do Windows Communication Foundation.
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.
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.