2 // System.Web.Services.Protocols.DiscoveryClientProtocol.cs
5 // Dave Bettin (javabettin@yahoo.com)
6 // Lluis Sanchez Gual (lluis@ximian.com)
8 // Copyright (C) Dave Bettin, 2002
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System
.Collections
;
34 using System
.Web
.Services
.Protocols
;
35 using System
.Web
.Services
.Description
;
37 using System
.Xml
.Schema
;
38 using System
.Xml
.Serialization
;
40 using System
.Text
.RegularExpressions
;
42 namespace System
.Web
.Services
.Discovery
{
43 public class DiscoveryClientProtocol
: HttpWebClientProtocol
{
47 private IList additionalInformation
= new ArrayList ();
48 private DiscoveryClientDocumentCollection documents
= new DiscoveryClientDocumentCollection();
49 private DiscoveryExceptionDictionary errors
= new DiscoveryExceptionDictionary();
50 private DiscoveryClientReferenceCollection references
= new DiscoveryClientReferenceCollection();
56 public DiscoveryClientProtocol ()
60 #endregion // Constructors
64 public IList AdditionalInformation
{
65 get { return additionalInformation; }
68 public DiscoveryClientDocumentCollection Documents
{
69 get { return documents; }
72 public DiscoveryExceptionDictionary Errors
{
73 get { return errors; }
76 public DiscoveryClientReferenceCollection References
{
77 get { return references; }
80 #endregion // Properties
84 public DiscoveryDocument
Discover (string url
)
86 Stream stream
= Download (ref url
);
87 XmlTextReader reader
= new XmlTextReader (url
, stream
);
88 if (!DiscoveryDocument
.CanRead (reader
))
89 throw new InvalidOperationException ("The url '" + url
+ "' does not point to a valid discovery document");
91 DiscoveryDocument doc
= DiscoveryDocument
.Read (reader
);
93 documents
.Add (url
, doc
);
94 AddDiscoReferences (doc
);
98 public DiscoveryDocument
DiscoverAny (string url
)
102 string contentType
= null;
103 Stream stream
= Download (ref url
, ref contentType
);
105 if (contentType
.IndexOf ("text/html") != -1)
107 // Look for an alternate url
109 StreamReader sr
= new StreamReader (stream
);
110 string str
= sr
.ReadToEnd ();
112 string rex
= "link\\s*rel\\s*=\\s*[\"']?alternate[\"']?\\s*";
113 rex
+= "type\\s*=\\s*[\"']?text/xml[\"']?\\s*href\\s*=\\s*(?:\"(?<1>[^\"]*)\"|'(?<1>[^']*)'|(?<1>\\S+))";
114 Regex rob
= new Regex (rex
, RegexOptions
.IgnoreCase
);
115 Match m
= rob
.Match (str
);
117 throw new InvalidOperationException ("The HTML document does not contain Web service discovery information");
119 if (url
.StartsWith ("/"))
121 Uri uri
= new Uri (url
);
122 url
= uri
.GetLeftPart (UriPartial
.Authority
) + m
.Groups
[1];
126 int i
= url
.LastIndexOf ('/');
128 throw new InvalidOperationException ("The HTML document does not contain Web service discovery information");
129 url
= url
.Substring (0,i
+1) + m
.Groups
[1];
131 stream
= Download (ref url
);
134 XmlTextReader reader
= new XmlTextReader (url
, stream
);
135 reader
.MoveToContent ();
136 DiscoveryDocument doc
;
137 DiscoveryReference refe
= null;
139 if (DiscoveryDocument
.CanRead (reader
))
141 doc
= DiscoveryDocument
.Read (reader
);
142 documents
.Add (url
, doc
);
143 refe
= new DiscoveryDocumentReference ();
144 AddDiscoReferences (doc
);
146 else if (ServiceDescription
.CanRead (reader
))
148 ServiceDescription wsdl
= ServiceDescription
.Read (reader
);
149 documents
.Add (url
, wsdl
);
150 doc
= new DiscoveryDocument ();
151 refe
= new ContractReference ();
152 doc
.References
.Add (refe
);
154 ((ContractReference
)refe
).ResolveInternal (this, wsdl
);
158 XmlSchema schema
= XmlSchema
.Read (reader
, null);
159 documents
.Add (url
, schema
);
160 doc
= new DiscoveryDocument ();
161 refe
= new SchemaReference ();
162 doc
.References
.Add (refe
);
165 refe
.ClientProtocol
= this;
167 references
.Add (url
, refe
);
172 catch (DiscoveryException ex
) {
177 void AddDiscoReferences (DiscoveryDocument doc
)
179 foreach (DiscoveryReference re
in doc
.References
)
181 re
.ClientProtocol
= this;
182 references
.Add (re
.Url
, re
);
185 if (doc
.AdditionalInfo
!= null) {
186 foreach (object info
in doc
.AdditionalInfo
)
187 additionalInformation
.Add (info
);
191 public Stream
Download (ref string url
)
193 string contentType
= null;
194 return Download (ref url
, ref contentType
);
197 public Stream
Download (ref string url
, ref string contentType
)
199 if (url
.StartsWith ("http://") || url
.StartsWith ("https://"))
201 WebRequest request
= GetWebRequest (new Uri(url
));
202 WebResponse resp
= request
.GetResponse ();
203 contentType
= resp
.ContentType
;
204 return resp
.GetResponseStream ();
206 else if (url
.StartsWith ("file://"))
208 WebRequest request
= WebRequest
.Create (new Uri (url
));
209 WebResponse resp
= request
.GetResponse ();
210 contentType
= resp
.ContentType
;
211 return resp
.GetResponseStream ();
215 string ext
= Path
.GetExtension (url
).ToLower();
216 if (ext
== ".wsdl" || ext
== ".xsd")
218 contentType
= "text/xml";
219 return new FileStream (url
, FileMode
.Open
, FileAccess
.Read
);
222 throw new InvalidOperationException ("Unrecognized file type '" + url
+ "'. Extension must be one of .wsdl or .xsd");
226 public DiscoveryClientResultCollection
ReadAll (string topLevelFilename
)
228 StreamReader sr
= new StreamReader (topLevelFilename
);
229 XmlSerializer ser
= new XmlSerializer (typeof (DiscoveryClientResultsFile
));
230 DiscoveryClientResultsFile resfile
= (DiscoveryClientResultsFile
) ser
.Deserialize (sr
);
233 foreach (DiscoveryClientResult dcr
in resfile
.Results
)
235 Type type
= Type
.GetType (dcr
.ReferenceTypeName
);
236 DiscoveryReference dr
= (DiscoveryReference
) Activator
.CreateInstance (type
);
238 FileStream fs
= new FileStream (dcr
.Filename
, FileMode
.Open
, FileAccess
.Read
);
239 Documents
.Add (dr
.Url
, dr
.ReadDocument (fs
));
241 References
.Add (dr
.Url
, dr
);
243 return resfile
.Results
;
246 public void ResolveAll ()
248 ArrayList list
= new ArrayList (References
.Values
);
249 foreach (DiscoveryReference re
in list
)
253 if (re
is DiscoveryDocumentReference
)
254 ((DiscoveryDocumentReference
)re
).ResolveAll ();
258 catch (DiscoveryException ex
)
260 Errors
[ex
.Url
] = ex
.Exception
;
264 Errors
[re
.Url
] = ex
;
269 public void ResolveOneLevel ()
271 ArrayList list
= new ArrayList (References
.Values
);
272 foreach (DiscoveryReference re
in list
)
276 public DiscoveryClientResultCollection
WriteAll (string directory
, string topLevelFilename
)
278 DiscoveryClientResultsFile resfile
= new DiscoveryClientResultsFile();
280 foreach (DiscoveryReference re
in References
.Values
)
282 object doc
= Documents
[re
.Url
];
283 if (doc
== null) continue;
285 string fileName
= FindValidName (resfile
, re
.DefaultFilename
);
286 resfile
.Results
.Add (new DiscoveryClientResult (re
.GetType(), re
.Url
, fileName
));
288 string filepath
= Path
.Combine (directory
, fileName
);
289 FileStream fs
= new FileStream (filepath
, FileMode
.Create
, FileAccess
.Write
);
290 re
.WriteDocument (doc
, fs
);
294 StreamWriter sw
= new StreamWriter (Path
.Combine (directory
, topLevelFilename
));
295 XmlSerializer ser
= new XmlSerializer (typeof (DiscoveryClientResultsFile
));
296 ser
.Serialize (sw
, resfile
);
298 return resfile
.Results
;
301 string FindValidName (DiscoveryClientResultsFile resfile
, string baseName
)
303 string name
= baseName
;
309 foreach (DiscoveryClientResult res
in resfile
.Results
)
311 if (name
== res
.Filename
) {
316 name
= Path
.GetFileNameWithoutExtension (baseName
) + (++id
) + Path
.GetExtension (baseName
);
323 #endregion // Methods
327 public sealed class DiscoveryClientResultsFile
{
331 private DiscoveryClientResultCollection results
;
337 public DiscoveryClientResultsFile ()
339 results
= new DiscoveryClientResultCollection ();
342 #endregion // Constructors
346 public DiscoveryClientResultCollection Results
{
347 get { return results; }
350 #endregion // Properties
353 #endregion // Classes
356 internal class DiscoveryException
: Exception
359 public Exception Exception
;
361 public DiscoveryException (string url
, Exception origin
)