1 #region Copyright (c) Microsoft Corporation
2 /// <copyright company='Microsoft Corporation'>
3 /// Copyright (c) Microsoft Corporation. All Rights Reserved.
4 /// Information Contained Herein is Proprietary and Confidential.
9 using System.Diagnostics;
12 using System.Xml.Schema;
13 using Discovery = System.Web.Services.Discovery;
14 using Description = System.Web.Services.Description;
15 using MetadataSection = System.ServiceModel.Description.MetadataSection;
16 using XmlSerialization = System.Xml.Serialization;
18 #if WEB_EXTENSIONS_CODE
19 using System.Web.Resources;
20 using System.Diagnostics.CodeAnalysis;
22 using Microsoft.VSDesigner.WCF.Resources;
25 #if WEB_EXTENSIONS_CODE
26 namespace System.Web.Compilation.WCFModel
28 namespace Microsoft.VSDesigner.WCFModel
32 /// This class presents a single metadata file in the ReferenceGroup
34 /// <remarks></remarks>
35 #if WEB_EXTENSIONS_CODE
36 internal class MetadataFile : ExternalFile
39 public class MetadataFile : ExternalFile
44 public const string DEFAULT_FILE_NAME = "service";
46 private MetadataType m_MetadataType;
47 private string m_SourceUrl;
52 private int m_SourceId;
54 // properties to merge metadata
55 private bool m_Ignore;
56 private bool m_IsMergeResult;
58 private int SOURCE_ID_NOT_SPECIFIED = 0;
60 private MetadataContent m_CachedMetadata;
62 // Content of the metadata file, one of them must be
63 private byte[] m_BinaryContent;
68 /// <remarks> Must support a default construct for XmlSerializer</remarks>
71 m_ID = Guid.NewGuid().ToString();
72 m_BinaryContent = new byte[] { };
79 /// <param name="Name">File Name</param>
80 /// <param name="Url">SourceUrl</param>
81 /// <param name="Content">File Content</param>
82 /// <remarks></remarks>
83 public MetadataFile(string name, string url, string content)
86 m_ID = Guid.NewGuid().ToString();
92 throw new ArgumentNullException("content");
101 /// <param name="Name">File Name</param>
102 /// <param name="Url">SourceUrl</param>
103 /// <param name="byteContent">File Content</param>
104 /// <remarks></remarks>
105 public MetadataFile(string name, string url, byte[] byteContent)
108 m_ID = Guid.NewGuid().ToString();
112 if (byteContent == null)
114 throw new ArgumentNullException("byteContent");
117 LoadContent(byteContent);
121 /// Retrieves the file content in binary format
124 /// <remarks></remarks>
125 public byte[] BinaryContent
129 return m_BinaryContent;
137 /// <remarks></remarks>
138 private MetadataContent CachedMetadata
142 if (m_CachedMetadata == null)
144 m_CachedMetadata = LoadMetadataContent(m_MetadataType);
146 return m_CachedMetadata;
152 /// Retrieves the file content
155 /// <remarks></remarks>
156 public string Content
160 StreamReader memReader = new StreamReader(new MemoryStream(m_BinaryContent));
161 return memReader.ReadToEnd();
166 /// The Type of Metadata
169 /// <remarks></remarks>
170 [XmlSerialization.XmlAttribute("MetadataType")]
171 public MetadataType FileType
175 return m_MetadataType;
179 m_MetadataType = value;
184 /// GUID string, it is used to track a metadata item (when it is updated)
187 /// <remarks></remarks>
188 [XmlSerialization.XmlAttribute()]
202 /// If it is true, the metadata file will be ignored by the code generator
205 /// <remarks></remarks>
206 [XmlSerialization.XmlAttribute()]
220 /// A special attribute used by XmlSerializer to decide whether Ignore attribute exists
223 /// <remarks></remarks>
224 [XmlSerialization.XmlIgnore()]
225 public bool IgnoreSpecified
241 /// whether the metadata file is a result of merging
244 /// <remarks></remarks>
245 [XmlSerialization.XmlAttribute()]
246 public bool IsMergeResult
250 return m_IsMergeResult;
254 m_IsMergeResult = value;
259 /// A special attribute used by XmlSerializer to decide whether IsMergeResult attribute exists
262 /// <remarks></remarks>
263 [XmlSerialization.XmlIgnore()]
264 public bool IsMergeResultSpecified
268 return m_IsMergeResult;
274 m_IsMergeResult = false;
280 /// Retrieves the content of a discovery file
283 /// <remarks></remarks>
284 public Discovery.DiscoveryDocument MetadataDiscoveryDocument
288 return CachedMetadata.MetadataDiscoveryDocument;
296 /// <remarks></remarks>
297 [XmlSerialization.XmlIgnore()]
298 public Exception MetadataFormatError
302 return CachedMetadata.MetadataFormatError;
307 /// Retrieves the content of a WSDL file
310 /// <remarks></remarks>
311 public Description.ServiceDescription MetadataServiceDescription
315 return CachedMetadata.MetadataServiceDescription;
320 /// Retrieves the content of a schema file
323 /// <remarks></remarks>
324 public XmlSchema MetadataXmlSchema
328 return CachedMetadata.MetadataXmlSchema;
333 /// Retrieves the content of an Xml file
336 /// <remarks></remarks>
337 public XmlDocument MetadataXmlDocument
341 return CachedMetadata.MetadataXmlDocument;
346 /// the SourceId links the the SourceId in the MetadataSource table
349 /// <remarks></remarks>
350 [XmlSerialization.XmlAttribute()]
361 Debug.Fail("Source ID shouldn't be a nagtive number");
362 throw new ArgumentException(WCFModelStrings.ReferenceGroup_InvalidSourceId);
369 /// A special attribute used by XmlSerializer to decide whether SourceId attribute exists
372 /// <remarks></remarks>
373 [XmlSerialization.XmlIgnore()]
374 public bool SourceIdSpecified
378 return m_SourceId != SOURCE_ID_NOT_SPECIFIED;
384 m_SourceId = SOURCE_ID_NOT_SPECIFIED;
390 /// The sourceUrl of the metadata file
393 /// <remarks></remarks>
394 [XmlSerialization.XmlAttribute()]
395 public string SourceUrl
408 /// Retrieves the TargetNamespace when it is a schema item or a WSDL item
411 /// <remarks></remarks>
412 public string TargetNamespace
416 return CachedMetadata.TargetNamespace;
421 /// Detemine the type of a metadata item
423 /// <param name="reader"></param>
424 /// <returns>File Type</returns>
425 /// <remarks></remarks>
426 private MetadataType DetermineFileType(XmlReader reader)
430 if (reader.IsStartElement(XmlStrings.WSDL.Elements.Root, XmlStrings.WSDL.NamespaceUri))
432 return MetadataType.Wsdl;
434 else if (reader.IsStartElement(XmlStrings.XmlSchema.Elements.Root, XmlStrings.XmlSchema.NamespaceUri))
436 return MetadataType.Schema;
438 else if (reader.IsStartElement(XmlStrings.WSPolicy.Elements.Policy, XmlStrings.WSPolicy.NamespaceUri)
439 || reader.IsStartElement(XmlStrings.WSPolicy.Elements.Policy, XmlStrings.WSPolicy.NamespaceUri15))
441 return MetadataType.Policy;
443 else if (reader.IsStartElement(XmlStrings.DISCO.Elements.Root, XmlStrings.DISCO.NamespaceUri))
445 return MetadataType.Disco;
447 else if (reader.IsStartElement(XmlStrings.DataServices.Elements.Root, XmlStrings.DataServices.NamespaceUri))
449 return MetadataType.Edmx;
453 return MetadataType.Xml;
458 // This must mean that the document isn't an XML Document so we continue trying other things...
459 return MetadataType.Unknown;
464 /// return the default extension
466 /// <return></return>
467 /// <remarks></remarks>
468 public string GetDefaultExtension()
470 switch (m_MetadataType)
472 case MetadataType.Disco:
474 case MetadataType.Wsdl:
476 case MetadataType.Schema:
478 case MetadataType.Xml:
480 case MetadataType.Policy:
482 case MetadataType.Edmx:
490 /// return the default filename without extension
492 /// <return></return>
493 /// <remarks></remarks>
494 public string GetDefaultFileName()
496 if (!String.IsNullOrEmpty(TargetNamespace))
498 string ns = TargetNamespace;
499 if (!ns.EndsWith("/", StringComparison.Ordinal))
501 int i = ns.LastIndexOfAny(Path.GetInvalidFileNameChars());
504 ns = ns.Substring(i + 1);
507 string defaultExtension = "." + GetDefaultExtension();
508 if (ns.Length > defaultExtension.Length && ns.EndsWith(defaultExtension, StringComparison.OrdinalIgnoreCase))
510 ns = ns.Substring(0, ns.Length - defaultExtension.Length);
520 return DEFAULT_FILE_NAME;
524 /// Load the content of a Metadata item into the object model
526 /// <param name="byteContent"></param>
527 /// <remarks></remarks>
528 internal void LoadContent(byte[] byteContent)
530 m_BinaryContent = byteContent;
531 LoadContentFromTextReader(new StreamReader(new MemoryStream(byteContent)));
535 /// Load the content of a Metadata item into the object model
537 /// <param name="content"></param>
538 /// <remarks></remarks>
539 internal void LoadContent(string content)
541 MemoryStream memStream = new MemoryStream();
542 StreamWriter contentWriter = new StreamWriter(memStream);
543 contentWriter.Write(content);
544 contentWriter.Flush();
545 m_BinaryContent = memStream.ToArray();
547 LoadContentFromTextReader(new StringReader(content));
551 /// Load the content of a Metadata item into the object model
553 /// <param name="contentReader"></param>
554 /// <remarks></remarks>
555 [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "Legacy code that trusts our developer-controlled input.")]
556 private void LoadContentFromTextReader(TextReader contentReader)
558 if (contentReader == null)
560 throw new ArgumentNullException("contentReader");
564 ErrorInLoading = null;
566 m_CachedMetadata = null;
568 using (XmlTextReader xmlReader = new XmlTextReader(contentReader))
570 if (m_MetadataType == MetadataType.Unknown)
572 // If we don't know the metedata type, we try to sniff it...
573 MetadataType fileType = DetermineFileType(xmlReader);
576 m_CachedMetadata = LoadMetadataContent(fileType, xmlReader);
577 if (m_CachedMetadata.MetadataFormatError == null)
579 m_MetadataType = fileType;
586 /// the function is called when the metadata is removed, and we need clean up the content
588 /// <remarks></remarks>
589 internal void CleanUpContent()
591 ErrorInLoading = null;
592 m_BinaryContent = new byte[] { };
594 m_CachedMetadata = null;
598 /// Load schema/wsdl model from binary content. -- Parse the metadata content
600 /// <return></return>
601 /// <remarks></remarks>
602 [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "Legacy code that trusts our developer-controlled input.")]
603 private MetadataContent LoadMetadataContent(MetadataType fileType)
605 if (ErrorInLoading != null)
607 return new MetadataContent(ErrorInLoading);
609 using (XmlTextReader xmlReader = new XmlTextReader(new StreamReader(new MemoryStream(m_BinaryContent))))
611 return LoadMetadataContent(fileType, xmlReader);
616 /// Load schema/wsdl model from text reader. -- it will parse the metadata content.
618 /// <return></return>
619 /// <remarks></remarks>
620 private MetadataContent LoadMetadataContent(MetadataType fileType, XmlTextReader xmlReader)
622 MetadataContent cachedMetadata = new MetadataContent();
628 case MetadataType.Disco:
629 cachedMetadata = new MetadataContent(Discovery.DiscoveryDocument.Read(xmlReader));
631 case MetadataType.Wsdl:
632 cachedMetadata = new MetadataContent(Description.ServiceDescription.Read(xmlReader));
633 cachedMetadata.MetadataServiceDescription.RetrievalUrl = GetMetadataSourceUrl();
635 case MetadataType.Schema:
636 cachedMetadata = new MetadataContent(XmlSchema.Read(xmlReader, null));
637 cachedMetadata.MetadataXmlSchema.SourceUri = GetMetadataSourceUrl();
639 case MetadataType.Unknown:
640 // For unknown types, we don't do nothing...
643 Debug.Assert(fileType == MetadataType.Xml || fileType == MetadataType.Policy || fileType == MetadataType.Edmx);
644 XmlDocument tempDoc = new XmlDocument();
645 tempDoc.Load(xmlReader);
646 cachedMetadata = new MetadataContent(tempDoc);
652 cachedMetadata = new MetadataContent(ex);
655 return cachedMetadata;
659 /// convert metadata file to MetadataSection (to feed code/proxy generator)
660 /// We don't reuse the buffered object model, because the generator could modify & corrupt them.
662 /// <remarks></remarks>
663 internal MetadataSection CreateMetadataSection()
665 MetadataContent metadata = LoadMetadataContent(m_MetadataType);
666 if (metadata.MetadataFormatError != null)
668 throw metadata.MetadataFormatError;
671 MetadataSection metadataSection = null;
675 case MetadataType.Unknown:
677 case MetadataType.Disco:
678 if (metadata.MetadataServiceDescription != null)
680 metadataSection = MetadataSection.CreateFromServiceDescription(metadata.MetadataServiceDescription);
683 case MetadataType.Wsdl:
684 // We need to make a copy of the WSDL object model since the act of importing it actuall
685 // modifies it, and we don't want the cached instance to be polluted...
686 System.Web.Services.Description.ServiceDescription description = metadata.MetadataServiceDescription;
687 if (description != null)
689 metadataSection = MetadataSection.CreateFromServiceDescription(description);
692 case MetadataType.Schema:
693 if (metadata.MetadataXmlSchema != null)
695 metadataSection = MetadataSection.CreateFromSchema(metadata.MetadataXmlSchema);
698 case MetadataFile.MetadataType.Policy:
699 if (metadata.MetadataXmlDocument != null)
701 metadataSection = MetadataSection.CreateFromPolicy(metadata.MetadataXmlDocument.DocumentElement, null);
704 case MetadataFile.MetadataType.Xml:
705 case MetadataFile.MetadataType.Edmx:
706 if (metadata.MetadataXmlDocument != null)
708 metadataSection = new MetadataSection(null, null, metadata.MetadataXmlDocument.DocumentElement);
712 System.Diagnostics.Debug.Fail("Unknown Type?");
715 return metadataSection;
719 /// Metadata source Url is used in error messages
721 /// <remarks></remarks>
722 internal string GetMetadataSourceUrl()
724 if (String.IsNullOrEmpty(SourceUrl))
735 /// Metadata File Type Enum
737 /// <remarks></remarks>
738 public enum MetadataType
740 [XmlSerialization.XmlEnum(Name = "Unknown")]
742 [XmlSerialization.XmlEnum(Name = "Disco")]
744 [XmlSerialization.XmlEnum(Name = "Wsdl")]
746 [XmlSerialization.XmlEnum(Name = "Schema")]
748 [XmlSerialization.XmlEnum(Name = "Policy")]
750 [XmlSerialization.XmlEnum(Name = "Xml")]
752 [XmlSerialization.XmlEnum(Name = "Edmx")]
757 /// Metadata contained inside the file. Only one of field is valid, which depends on the MetadataType
759 /// <remarks></remarks>
760 private class MetadataContent
763 private Discovery.DiscoveryDocument m_MetadataDiscoveryDocument;
764 private Description.ServiceDescription m_MetadataServiceDescription;
765 private XmlSchema m_MetadataXmlSchema;
766 private XmlDocument m_MetadataXmlDocument;
768 private Exception m_MetadataFormatError;
770 private string m_TargetNamespace;
772 internal MetadataContent()
774 m_TargetNamespace = String.Empty;
777 internal MetadataContent(Discovery.DiscoveryDocument discoveryDocument)
779 m_MetadataDiscoveryDocument = discoveryDocument;
780 m_TargetNamespace = String.Empty;
783 internal MetadataContent(Description.ServiceDescription serviceDescription)
785 m_MetadataServiceDescription = serviceDescription;
786 m_TargetNamespace = serviceDescription.TargetNamespace;
789 internal MetadataContent(XmlSchema schema)
791 m_MetadataXmlSchema = schema;
792 m_TargetNamespace = schema.TargetNamespace;
795 internal MetadataContent(XmlDocument document)
797 m_MetadataXmlDocument = document;
798 m_TargetNamespace = String.Empty;
801 internal MetadataContent(Exception metadataFormatError)
803 m_MetadataFormatError = metadataFormatError;
807 /// Retrieves the content of a discovery file
810 /// <remarks></remarks>
811 public Discovery.DiscoveryDocument MetadataDiscoveryDocument
815 return m_MetadataDiscoveryDocument;
823 /// <remarks></remarks>
824 public Exception MetadataFormatError
828 return m_MetadataFormatError;
833 /// Retrieves the content of a WSDL file
836 /// <remarks></remarks>
837 public Description.ServiceDescription MetadataServiceDescription
841 return m_MetadataServiceDescription;
846 /// Retrieves the content of a schema file
849 /// <remarks></remarks>
850 public XmlSchema MetadataXmlSchema
854 return m_MetadataXmlSchema;
859 /// Retrieves the content of an Xml file
862 /// <remarks></remarks>
863 public XmlDocument MetadataXmlDocument
867 return m_MetadataXmlDocument;
872 /// Retrieves the TargetNamespace when it is a schema item or a WSDL item
875 /// <remarks></remarks>
876 public string TargetNamespace
880 return m_TargetNamespace;