1 //------------------------------------------------------------ 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //------------------------------------------------------------ 4 5 namespace System.ServiceModel.Syndication 6 { 7 using System.IO; 8 using System.Runtime; 9 using System.Runtime.Serialization; 10 using System.Xml; 11 using System.Xml.Serialization; 12 using System.Runtime.CompilerServices; 13 14 [TypeForwardedFrom("System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")] 15 public class SyndicationElementExtension 16 { 17 XmlBuffer buffer; 18 int bufferElementIndex; 19 // extensionData and extensionDataWriter are only present on the send side 20 object extensionData; 21 ExtensionDataWriter extensionDataWriter; 22 string outerName; 23 string outerNamespace; 24 SyndicationElementExtension(XmlReader xmlReader)25 public SyndicationElementExtension(XmlReader xmlReader) 26 { 27 if (xmlReader == null) 28 { 29 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("xmlReader"); 30 } 31 SyndicationFeedFormatter.MoveToStartElement(xmlReader); 32 this.outerName = xmlReader.LocalName; 33 this.outerNamespace = xmlReader.NamespaceURI; 34 this.buffer = new XmlBuffer(int.MaxValue); 35 using (XmlDictionaryWriter writer = this.buffer.OpenSection(XmlDictionaryReaderQuotas.Max)) 36 { 37 writer.WriteStartElement(Rss20Constants.ExtensionWrapperTag); 38 writer.WriteNode(xmlReader, false); 39 writer.WriteEndElement(); 40 } 41 buffer.CloseSection(); 42 buffer.Close(); 43 this.bufferElementIndex = 0; 44 } 45 SyndicationElementExtension(object dataContractExtension)46 public SyndicationElementExtension(object dataContractExtension) 47 : this(dataContractExtension, (XmlObjectSerializer) null) 48 { 49 } 50 SyndicationElementExtension(object dataContractExtension, XmlObjectSerializer dataContractSerializer)51 public SyndicationElementExtension(object dataContractExtension, XmlObjectSerializer dataContractSerializer) 52 : this(null, null, dataContractExtension, dataContractSerializer) 53 { 54 } 55 SyndicationElementExtension(string outerName, string outerNamespace, object dataContractExtension)56 public SyndicationElementExtension(string outerName, string outerNamespace, object dataContractExtension) 57 : this(outerName, outerNamespace, dataContractExtension, null) 58 { 59 } 60 SyndicationElementExtension(string outerName, string outerNamespace, object dataContractExtension, XmlObjectSerializer dataContractSerializer)61 public SyndicationElementExtension(string outerName, string outerNamespace, object dataContractExtension, XmlObjectSerializer dataContractSerializer) 62 { 63 if (dataContractExtension == null) 64 { 65 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dataContractExtension"); 66 } 67 if (outerName == string.Empty) 68 { 69 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.OuterNameOfElementExtensionEmpty)); 70 } 71 if (dataContractSerializer == null) 72 { 73 dataContractSerializer = new DataContractSerializer(dataContractExtension.GetType()); 74 } 75 this.outerName = outerName; 76 this.outerNamespace = outerNamespace; 77 this.extensionData = dataContractExtension; 78 this.extensionDataWriter = new ExtensionDataWriter(this.extensionData, dataContractSerializer, this.outerName, this.outerNamespace); 79 } 80 SyndicationElementExtension(object xmlSerializerExtension, XmlSerializer serializer)81 public SyndicationElementExtension(object xmlSerializerExtension, XmlSerializer serializer) 82 { 83 if (xmlSerializerExtension == null) 84 { 85 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("xmlSerializerExtension"); 86 } 87 if (serializer == null) 88 { 89 serializer = new XmlSerializer(xmlSerializerExtension.GetType()); 90 } 91 this.extensionData = xmlSerializerExtension; 92 this.extensionDataWriter = new ExtensionDataWriter(this.extensionData, serializer); 93 } 94 SyndicationElementExtension(XmlBuffer buffer, int bufferElementIndex, string outerName, string outerNamespace)95 internal SyndicationElementExtension(XmlBuffer buffer, int bufferElementIndex, string outerName, string outerNamespace) 96 { 97 this.buffer = buffer; 98 this.bufferElementIndex = bufferElementIndex; 99 this.outerName = outerName; 100 this.outerNamespace = outerNamespace; 101 } 102 103 public string OuterName 104 { 105 get 106 { 107 if (this.outerName == null) 108 { 109 EnsureOuterNameAndNs(); 110 } 111 return this.outerName; 112 } 113 } 114 115 public string OuterNamespace 116 { 117 get 118 { 119 if (this.outerName == null) 120 { 121 EnsureOuterNameAndNs(); 122 } 123 return this.outerNamespace; 124 } 125 } 126 GetObject()127 public TExtension GetObject<TExtension>() 128 { 129 return GetObject<TExtension>(new DataContractSerializer(typeof(TExtension))); 130 } 131 GetObject(XmlObjectSerializer serializer)132 public TExtension GetObject<TExtension>(XmlObjectSerializer serializer) 133 { 134 if (serializer == null) 135 { 136 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serializer"); 137 } 138 if (this.extensionData != null && typeof(TExtension).IsAssignableFrom(extensionData.GetType())) 139 { 140 return (TExtension) this.extensionData; 141 } 142 using (XmlReader reader = GetReader()) 143 { 144 return (TExtension) serializer.ReadObject(reader, false); 145 } 146 } 147 GetObject(XmlSerializer serializer)148 public TExtension GetObject<TExtension>(XmlSerializer serializer) 149 { 150 if (serializer == null) 151 { 152 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serializer"); 153 } 154 if (this.extensionData != null && typeof(TExtension).IsAssignableFrom(extensionData.GetType())) 155 { 156 return (TExtension) this.extensionData; 157 } 158 using (XmlReader reader = GetReader()) 159 { 160 return (TExtension) serializer.Deserialize(reader); 161 } 162 } 163 GetReader()164 public XmlReader GetReader() 165 { 166 this.EnsureBuffer(); 167 XmlReader reader = this.buffer.GetReader(0); 168 int index = 0; 169 reader.ReadStartElement(Rss20Constants.ExtensionWrapperTag); 170 while (reader.IsStartElement()) 171 { 172 if (index == this.bufferElementIndex) 173 { 174 break; 175 } 176 ++index; 177 reader.Skip(); 178 } 179 return reader; 180 } 181 WriteTo(XmlWriter writer)182 public void WriteTo(XmlWriter writer) 183 { 184 if (writer == null) 185 { 186 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer"); 187 } 188 if (this.extensionDataWriter != null) 189 { 190 this.extensionDataWriter.WriteTo(writer); 191 } 192 else 193 { 194 using (XmlReader reader = GetReader()) 195 { 196 writer.WriteNode(reader, false); 197 } 198 } 199 } 200 EnsureBuffer()201 void EnsureBuffer() 202 { 203 if (this.buffer == null) 204 { 205 this.buffer = new XmlBuffer(int.MaxValue); 206 using (XmlDictionaryWriter writer = this.buffer.OpenSection(XmlDictionaryReaderQuotas.Max)) 207 { 208 writer.WriteStartElement(Rss20Constants.ExtensionWrapperTag); 209 this.WriteTo(writer); 210 writer.WriteEndElement(); 211 } 212 buffer.CloseSection(); 213 buffer.Close(); 214 this.bufferElementIndex = 0; 215 } 216 } 217 EnsureOuterNameAndNs()218 void EnsureOuterNameAndNs() 219 { 220 Fx.Assert(this.extensionDataWriter != null, "outer name is null only for datacontract and xmlserializer cases"); 221 this.extensionDataWriter.ComputeOuterNameAndNs(out this.outerName, out this.outerNamespace); 222 } 223 224 // this class holds the extension data and the associated serializer (either DataContractSerializer or XmlSerializer but not both) 225 class ExtensionDataWriter 226 { 227 readonly XmlObjectSerializer dataContractSerializer; 228 readonly object extensionData; 229 readonly string outerName; 230 readonly string outerNamespace; 231 readonly XmlSerializer xmlSerializer; 232 ExtensionDataWriter(object extensionData, XmlObjectSerializer dataContractSerializer, string outerName, string outerNamespace)233 public ExtensionDataWriter(object extensionData, XmlObjectSerializer dataContractSerializer, string outerName, string outerNamespace) 234 { 235 Fx.Assert(extensionData != null && dataContractSerializer != null, "null check"); 236 this.dataContractSerializer = dataContractSerializer; 237 this.extensionData = extensionData; 238 this.outerName = outerName; 239 this.outerNamespace = outerNamespace; 240 } 241 ExtensionDataWriter(object extensionData, XmlSerializer serializer)242 public ExtensionDataWriter(object extensionData, XmlSerializer serializer) 243 { 244 Fx.Assert(extensionData != null && serializer != null, "null check"); 245 this.xmlSerializer = serializer; 246 this.extensionData = extensionData; 247 } 248 WriteTo(XmlWriter writer)249 public void WriteTo(XmlWriter writer) 250 { 251 if (this.xmlSerializer != null) 252 { 253 Fx.Assert((this.dataContractSerializer == null && this.outerName == null && this.outerNamespace == null), "Xml serializer cannot have outer name, ns"); 254 this.xmlSerializer.Serialize(writer, this.extensionData); 255 } 256 else 257 { 258 Fx.Assert(this.xmlSerializer == null, "Xml serializer cannot be configured"); 259 if (this.outerName != null) 260 { 261 writer.WriteStartElement(outerName, outerNamespace); 262 this.dataContractSerializer.WriteObjectContent(writer, this.extensionData); 263 writer.WriteEndElement(); 264 } 265 else 266 { 267 this.dataContractSerializer.WriteObject(writer, this.extensionData); 268 } 269 } 270 } 271 ComputeOuterNameAndNs(out string name, out string ns)272 internal void ComputeOuterNameAndNs(out string name, out string ns) 273 { 274 if (this.outerName != null) 275 { 276 Fx.Assert(this.xmlSerializer == null, "outer name is not null for data contract extension only"); 277 name = this.outerName; 278 ns = this.outerNamespace; 279 } 280 else if (this.dataContractSerializer != null) 281 { 282 Fx.Assert(this.xmlSerializer == null, "only one of xmlserializer or datacontract serializer can be present"); 283 XsdDataContractExporter dcExporter = new XsdDataContractExporter(); 284 XmlQualifiedName qName = dcExporter.GetRootElementName(this.extensionData.GetType()); 285 if (qName != null) 286 { 287 name = qName.Name; 288 ns = qName.Namespace; 289 } 290 else 291 { 292 // this can happen if an IXmlSerializable type is specified with IsAny=true 293 ReadOuterNameAndNs(out name, out ns); 294 } 295 } 296 else 297 { 298 Fx.Assert(this.dataContractSerializer == null, "only one of xmlserializer or datacontract serializer can be present"); 299 XmlReflectionImporter importer = new XmlReflectionImporter(); 300 XmlTypeMapping typeMapping = importer.ImportTypeMapping(this.extensionData.GetType()); 301 if (typeMapping != null && !string.IsNullOrEmpty(typeMapping.ElementName)) 302 { 303 name = typeMapping.ElementName; 304 ns = typeMapping.Namespace; 305 } 306 else 307 { 308 // this can happen if an IXmlSerializable type is specified with IsAny=true 309 ReadOuterNameAndNs(out name, out ns); 310 } 311 } 312 } 313 ReadOuterNameAndNs(out string name, out string ns)314 internal void ReadOuterNameAndNs(out string name, out string ns) 315 { 316 using (MemoryStream stream = new MemoryStream()) 317 { 318 using (XmlWriter writer = XmlWriter.Create(stream)) 319 { 320 this.WriteTo(writer); 321 } 322 stream.Seek(0, SeekOrigin.Begin); 323 using (XmlReader reader = XmlReader.Create(stream)) 324 { 325 SyndicationFeedFormatter.MoveToStartElement(reader); 326 name = reader.LocalName; 327 ns = reader.NamespaceURI; 328 } 329 } 330 } 331 } 332 } 333 } 334