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 reader.XmlResolver = null;
89 if (!DiscoveryDocument.CanRead (reader))
90 throw new InvalidOperationException ("The url '" + url + "' does not point to a valid discovery document");
92 DiscoveryDocument doc = DiscoveryDocument.Read (reader);
94 documents.Add (url, doc);
95 AddDiscoReferences (doc);
99 public DiscoveryDocument DiscoverAny (string url)
103 string contentType = null;
104 Stream stream = Download (ref url, ref contentType);
106 if (contentType.IndexOf ("text/html") != -1)
108 // Look for an alternate url
110 StreamReader sr = new StreamReader (stream);
111 string str = sr.ReadToEnd ();
113 string rex = "link\\s*rel\\s*=\\s*[\"']?alternate[\"']?\\s*";
114 rex += "type\\s*=\\s*[\"']?text/xml[\"']?\\s*href\\s*=\\s*(?:\"(?<1>[^\"]*)\"|'(?<1>[^']*)'|(?<1>\\S+))";
115 Regex rob = new Regex (rex, RegexOptions.IgnoreCase);
116 Match m = rob.Match (str);
118 throw new InvalidOperationException ("The HTML document does not contain Web service discovery information");
120 if (url.StartsWith ("/"))
122 Uri uri = new Uri (url);
123 url = uri.GetLeftPart (UriPartial.Authority) + m.Groups[1];
127 int i = url.LastIndexOf ('/');
129 throw new InvalidOperationException ("The HTML document does not contain Web service discovery information");
131 Uri tmp = new Uri (url);
132 tmp = new Uri (tmp, m.Groups [1].ToString ());
133 url = tmp.ToString ();
135 stream = Download (ref url);
138 XmlTextReader reader = new XmlTextReader (url, stream);
139 reader.XmlResolver = null;
140 reader.MoveToContent ();
141 DiscoveryDocument doc;
142 DiscoveryReference refe = null;
144 if (DiscoveryDocument.CanRead (reader))
146 doc = DiscoveryDocument.Read (reader);
147 documents.Add (url, doc);
148 refe = new DiscoveryDocumentReference ();
149 AddDiscoReferences (doc);
151 else if (ServiceDescription.CanRead (reader))
153 ServiceDescription wsdl = ServiceDescription.Read (reader);
154 documents.Add (url, wsdl);
155 doc = new DiscoveryDocument ();
156 refe = new ContractReference ();
157 doc.References.Add (refe);
159 ((ContractReference)refe).ResolveInternal (this, wsdl);
163 XmlSchema schema = XmlSchema.Read (reader, null);
164 documents.Add (url, schema);
165 doc = new DiscoveryDocument ();
166 refe = new SchemaReference ();
168 ((SchemaReference)refe).ResolveInternal (this, schema);
169 doc.References.Add (refe);
172 refe.ClientProtocol = this;
174 references.Add (url, refe);
179 catch (DiscoveryException ex) {
184 void AddDiscoReferences (DiscoveryDocument doc)
186 foreach (DiscoveryReference re in doc.References)
188 re.ClientProtocol = this;
189 references.Add (re.Url, re);
192 if (doc.AdditionalInfo != null) {
193 foreach (object info in doc.AdditionalInfo)
194 additionalInformation.Add (info);
198 public Stream Download (ref string url)
200 string contentType = null;
201 return Download (ref url, ref contentType);
204 public Stream Download (ref string url, ref string contentType)
206 if (url.StartsWith ("http://") || url.StartsWith ("https://"))
208 WebRequest request = GetWebRequest (new Uri(url));
209 WebResponse resp = request.GetResponse ();
210 contentType = resp.ContentType;
211 return resp.GetResponseStream ();
213 else if (url.StartsWith ("file://"))
215 WebRequest request = WebRequest.Create (new Uri (url));
216 WebResponse resp = request.GetResponse ();
217 contentType = resp.ContentType;
218 return resp.GetResponseStream ();
222 string ext = Path.GetExtension (url).ToLower();
223 if (ext == ".wsdl" || ext == ".xsd")
225 contentType = "text/xml";
226 return new FileStream (url, FileMode.Open, FileAccess.Read);
229 throw new InvalidOperationException ("Unrecognized file type '" + url + "'. Extension must be one of .wsdl or .xsd");
234 [System.Runtime.InteropServices.ComVisible (false)]
236 [Obsolete ("This method will be removed from a future version. The method call is no longer required for resource discovery", false)]
237 public void LoadExternals ()
241 public DiscoveryClientResultCollection ReadAll (string topLevelFilename)
243 StreamReader sr = new StreamReader (topLevelFilename);
244 XmlSerializer ser = new XmlSerializer (typeof (DiscoveryClientResultsFile));
245 DiscoveryClientResultsFile resfile = (DiscoveryClientResultsFile) ser.Deserialize (sr);
248 string basePath = Path.GetDirectoryName (topLevelFilename);
250 foreach (DiscoveryClientResult dcr in resfile.Results)
252 Type type = Type.GetType (dcr.ReferenceTypeName);
253 DiscoveryReference dr = (DiscoveryReference) Activator.CreateInstance (type);
255 FileStream fs = new FileStream (Path.Combine (basePath, dcr.Filename), FileMode.Open, FileAccess.Read);
256 Documents.Add (dr.Url, dr.ReadDocument (fs));
258 References.Add (dr.Url, dr);
260 return resfile.Results;
263 public void ResolveAll ()
265 ArrayList list = new ArrayList (References.Values);
266 foreach (DiscoveryReference re in list)
270 if (re is DiscoveryDocumentReference)
271 ((DiscoveryDocumentReference)re).ResolveAll ();
275 catch (DiscoveryException ex)
277 Errors [ex.Url] = ex.Exception;
281 Errors [re.Url] = ex;
286 public void ResolveOneLevel ()
288 ArrayList list = new ArrayList (References.Values);
289 foreach (DiscoveryReference re in list)
293 public DiscoveryClientResultCollection WriteAll (string directory, string topLevelFilename)
295 DiscoveryClientResultsFile resfile = new DiscoveryClientResultsFile();
297 foreach (DiscoveryReference re in References.Values)
299 object doc = Documents [re.Url];
300 if (doc == null) continue;
302 string fileName = FindValidName (resfile, re.DefaultFilename);
303 resfile.Results.Add (new DiscoveryClientResult (re.GetType(), re.Url, fileName));
305 string filepath = Path.Combine (directory, fileName);
306 FileStream fs = new FileStream (filepath, FileMode.Create, FileAccess.Write);
307 re.WriteDocument (doc, fs);
311 StreamWriter sw = new StreamWriter (Path.Combine (directory, topLevelFilename));
312 XmlSerializer ser = new XmlSerializer (typeof (DiscoveryClientResultsFile));
313 ser.Serialize (sw, resfile);
315 return resfile.Results;
318 string FindValidName (DiscoveryClientResultsFile resfile, string baseName)
320 string name = baseName;
326 foreach (DiscoveryClientResult res in resfile.Results)
328 if (name == res.Filename) {
333 name = Path.GetFileNameWithoutExtension (baseName) + (++id) + Path.GetExtension (baseName);
340 #endregion // Methods
344 public sealed class DiscoveryClientResultsFile {
348 private DiscoveryClientResultCollection results;
354 public DiscoveryClientResultsFile ()
356 results = new DiscoveryClientResultCollection ();
359 #endregion // Constructors
363 public DiscoveryClientResultCollection Results {
364 get { return results; }
367 #endregion // Properties
370 #endregion // Classes
373 internal class DiscoveryException : Exception
376 public Exception Exception;
378 public DiscoveryException (string url, Exception origin)