Ejemplo de extensiones con establecimiento inflexible de tipos
El ejemplo utiliza la clase SyndicationFeed para los fines del ejemplo. Sin embargo, los modelos mostrados en este ejemplo se pueden utilizar con todas las clases de sindicación que admiten los datos de la extensión:
Nota
Para generar y ejecutar este ejemplo, es necesario que esté instalado .NET Framework versión 3.5. Para abrir los archivos de solución y proyecto se necesita Visual Studio 2008.
El modelo de objetos de sindicación (SyndicationFeed, SyndicationItem y las clases relacionadas) admite el acceso con establecimiento flexible de tipos en datos de extensión utilizando las propiedades AttributeExtensions y ElementExtensions. Este ejemplo muestra cómo proporcionar acceso con establecimiento inflexible de tipos a los datos de extensión implementando clases derivadas personalizadas de SyndicationFeed y SyndicationItem que exponen ciertas extensiones específicas de la aplicación como propiedades con establecimiento inflexible de tipos.
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 sólo es para fines ilustrativos y este ejemplo no está diseñado para que sea una implementación completa de la especificación propuesta.
XML de ejemplo
El fragmento de código XML muestra una entrada de Atom 1.0 con un elemento de extensión In-reply-to adicional.
<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://purl.org/syndication/thread/1.0"
xmlns="http://purl.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 elemento <in-reply-to>
especifica tres atributos necesarios (ref, type y href) mientras que permite también la presencia de los atributos de extensión y elementos de extensión adicionales.
Modelar el elemento In-Reply-To
En este ejemplo, el elemento <in-reply-to>
se modela como CLR que implementa IXmlSerializable, habilitando su uso con DataContractSerializer. También implementa algunos métodos y propiedades para tener acceso a los datos del elemento, tal y como se muestra en el código de ejemplo siguiente.
[XmlRoot(ElementName = "in-reply-to", Namespace = "http://purl.org/syndication/thread/1.0")]
public class InReplyToElement : IXmlSerializable
{
internal const string ElementName = "in-reply-to";
internal const string NsUri =
"http://purl.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 clase InReplyToElement
implementa las propiedades para el atributo necesario (HRef, MediaType y Source) así como las colecciones para contener AttributeExtensions y ElementExtensions.
La clase InReplyToElement
implementa la interfaz IXmlSerializable, que permite el control directo sobre cómo se leen y se escriben las instancias del objeto en XML. El método ReadXml
lee primero los valores para las propiedades Ref, HRef, Source y MediaType de XmlReader pasado a él. Cualquier atributo desconocido se almacena en la colección AttributeExtensions. Cuando se hayan leído todos los atributos, se llama a ReadStartElement para avanzar el lector al elemento siguiente. Dado que el elemento modelado por esta clase no tiene ningún elemento secundario necesario, los elementos secundarios se almacenan en búfer en las instancias XElement y se almacenan en la colección ElementExtensions.
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 elemento externo propiamente dicho, como lo ha hecho el autor de la llamada de WriteXml
). También escribe el contenido de AttributeExtensions y ElementExtensions en el sistema de escritura.
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, la clase ThreadedItem
modela SyndicationItems
con extensiones InReplyTo
. De igual manera, la clase ThreadedFeed
es SyndicationFeed cuyos elementos son todos instancias de ThreadedItem
.
La clase ThreadedFeed
hereda de SyndicationFeed e invalida OnCreateItem para devolver un ThreadedItem
. También implementa un método para tener acceso a la colección Items
como ThreadedItems
.
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 con establecimiento inflexible de tipos. Esto proporciona acceso adecuado mediante programación a los datos de extensión InReplyTo
. También implementa TryParseElement
y WriteElementExtensions
para leer y escribir sus datos de extensión.
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, generar y ejecutar el ejemplo
Asegúrese de que ha realizado el Procedimiento de instalación único para ejemplos de Windows Communication Foundation.
Para generar el código C# o Visual Basic .NET Edition de la solución, siga las instrucciones de Generación de ejemplos de Windows Communication Foundation.
Para ejecutar el ejemplo en una configuración de equipos única o cruzada, siga las instrucciones de Ejecución de ejemplos de Windows Communication Foundation.
Copyright © 2007 Microsoft Corporation. Reservados todos los derechos.