Ejemplo de extensiones fuertemente tipadas
El ejemplo de StronglyTypedExtensions usa 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:
El modelo de objetos de distribución (SyndicationFeed, SyndicationItem y las clases relacionadas) admite el acceso fuertemente tipado en datos de extensión utilizando las propiedades AttributeExtensions y ElementExtensions. Este ejemplo 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 estén disponibles ciertas extensiones específicas de la aplicación 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 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 siguiente ejemplo de 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://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 elemento <in-reply-to>
especifica tres atributos necesarios (ref
, type
, y href
) mientras que permite también la presencia de 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, lo que habilita su uso con DataContractSerializer. También implementa algunos métodos y propiedades para acceder a los datos del elemento, tal y 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 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, como se muestra en el siguiente código.
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, 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, la clase SyndicationItems
modela InReplyTo
con extensiones ThreadedItem
. 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
, como se muestra en el siguiente código.
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 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 la 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);
}
}
Configurar, compilar y ejecutar el ejemplo
Asegúrese de que ha realizado el procedimiento de instalación única para los ejemplos de Windows Communication Foundation.
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.
Para ejecutar el ejemplo en una configuración de una sola máquina o de varias máquinas, siga las instrucciones que se indican en Ejecución de los ejemplos de Windows Communication Foundation.