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;
36 using System.Xml.Schema;
37 using System.Xml.Serialization;
39 using System.Text.RegularExpressions;
41 using System.Web.Services.Description;
44 namespace System.Web.Services.Discovery {
45 public class DiscoveryClientProtocol : HttpWebClientProtocol {
49 private IList additionalInformation = new ArrayList ();
50 private DiscoveryClientDocumentCollection documents = new DiscoveryClientDocumentCollection();
51 private DiscoveryExceptionDictionary errors = new DiscoveryExceptionDictionary();
52 private DiscoveryClientReferenceCollection references = new DiscoveryClientReferenceCollection();
58 public DiscoveryClientProtocol ()
62 #endregion // Constructors
66 public IList AdditionalInformation {
67 get { return additionalInformation; }
70 public DiscoveryClientDocumentCollection Documents {
71 get { return documents; }
74 public DiscoveryExceptionDictionary Errors {
75 get { return errors; }
78 public DiscoveryClientReferenceCollection References {
79 get { return references; }
82 #endregion // Properties
86 public DiscoveryDocument Discover (string url)
88 Stream stream = Download (ref url);
89 XmlTextReader reader = new XmlTextReader (url, stream);
90 reader.XmlResolver = null;
91 if (!DiscoveryDocument.CanRead (reader))
92 throw new InvalidOperationException ("The url '" + url + "' does not point to a valid discovery document");
94 DiscoveryDocument doc = DiscoveryDocument.Read (reader);
96 documents.Add (url, doc);
97 AddDiscoReferences (doc);
101 public DiscoveryDocument DiscoverAny (string url)
105 string contentType = null;
106 Stream stream = Download (ref url, ref contentType);
108 if (contentType.IndexOf ("text/html") != -1)
110 // Look for an alternate url
112 StreamReader sr = new StreamReader (stream);
113 string str = sr.ReadToEnd ();
115 string rex = "link\\s*rel\\s*=\\s*[\"']?alternate[\"']?\\s*";
116 rex += "type\\s*=\\s*[\"']?text/xml[\"']?\\s*href\\s*=\\s*(?:\"(?<1>[^\"]*)\"|'(?<1>[^']*)'|(?<1>\\S+))";
117 Regex rob = new Regex (rex, RegexOptions.IgnoreCase);
118 Match m = rob.Match (str);
120 throw new InvalidOperationException ("The HTML document does not contain Web service discovery information");
122 if (url.StartsWith ("/"))
124 Uri uri = new Uri (url);
125 url = uri.GetLeftPart (UriPartial.Authority) + m.Groups[1];
129 int i = url.LastIndexOf ('/');
131 throw new InvalidOperationException ("The HTML document does not contain Web service discovery information");
133 Uri tmp = new Uri (url);
134 tmp = new Uri (tmp, m.Groups [1].ToString ());
135 url = tmp.ToString ();
137 stream = Download (ref url);
140 XmlTextReader reader = new XmlTextReader (url, stream);
141 reader.XmlResolver = null;
142 reader.MoveToContent ();
143 DiscoveryDocument doc;
144 DiscoveryReference refe = null;
146 if (DiscoveryDocument.CanRead (reader))
148 doc = DiscoveryDocument.Read (reader);
149 documents.Add (url, doc);
150 refe = new DiscoveryDocumentReference ();
151 AddDiscoReferences (doc);
154 else if (ServiceDescription.CanRead (reader))
156 ServiceDescription wsdl = ServiceDescription.Read (reader);
157 documents.Add (url, wsdl);
158 doc = new DiscoveryDocument ();
159 refe = new ContractReference ();
160 doc.References.Add (refe);
162 ((ContractReference)refe).ResolveInternal (this, wsdl);
167 XmlSchema schema = XmlSchema.Read (reader, null);
168 documents.Add (url, schema);
169 doc = new DiscoveryDocument ();
170 refe = new SchemaReference ();
172 ((SchemaReference)refe).ResolveInternal (this, schema);
173 doc.References.Add (refe);
176 refe.ClientProtocol = this;
178 references.Add (url, refe);
183 catch (DiscoveryException ex) {
188 void AddDiscoReferences (DiscoveryDocument doc)
190 foreach (DiscoveryReference re in doc.References)
192 re.ClientProtocol = this;
193 references.Add (re.Url, re);
196 if (doc.AdditionalInfo != null) {
197 foreach (object info in doc.AdditionalInfo)
198 additionalInformation.Add (info);
202 public Stream Download (ref string url)
204 string contentType = null;
205 return Download (ref url, ref contentType);
208 public Stream Download (ref string url, ref string contentType)
210 if (url.StartsWith ("http://") || url.StartsWith ("https://"))
212 WebRequest request = GetWebRequest (new Uri(url));
213 WebResponse resp = request.GetResponse ();
214 contentType = resp.ContentType;
215 return resp.GetResponseStream ();
217 else if (url.StartsWith ("file://"))
219 WebRequest request = WebRequest.Create (new Uri (url));
220 WebResponse resp = request.GetResponse ();
221 contentType = resp.ContentType;
222 return resp.GetResponseStream ();
226 string ext = Path.GetExtension (url).ToLower();
227 if (ext == ".wsdl" || ext == ".xsd")
229 contentType = "text/xml";
230 return new FileStream (url, FileMode.Open, FileAccess.Read);
233 throw new InvalidOperationException ("Unrecognized file type '" + url + "'. Extension must be one of .wsdl or .xsd");
237 [System.Runtime.InteropServices.ComVisible (false)]
238 [Obsolete ("This method will be removed from a future version. The method call is no longer required for resource discovery", false)]
239 public void LoadExternals ()
243 public DiscoveryClientResultCollection ReadAll (string topLevelFilename)
245 StreamReader sr = new StreamReader (topLevelFilename);
246 XmlSerializer ser = new XmlSerializer (typeof (DiscoveryClientResultsFile));
247 DiscoveryClientResultsFile resfile = (DiscoveryClientResultsFile) ser.Deserialize (sr);
250 string basePath = Path.GetDirectoryName (topLevelFilename);
252 foreach (DiscoveryClientResult dcr in resfile.Results)
254 Type type = Type.GetType (dcr.ReferenceTypeName);
255 DiscoveryReference dr = (DiscoveryReference) Activator.CreateInstance (type);
257 FileStream fs = new FileStream (Path.Combine (basePath, dcr.Filename), FileMode.Open, FileAccess.Read);
258 Documents.Add (dr.Url, dr.ReadDocument (fs));
260 References.Add (dr.Url, dr);
262 return resfile.Results;
265 public void ResolveAll ()
267 ArrayList list = new ArrayList (References.Values);
268 foreach (DiscoveryReference re in list)
272 if (re is DiscoveryDocumentReference)
273 ((DiscoveryDocumentReference)re).ResolveAll ();
277 catch (DiscoveryException ex)
279 Errors [ex.Url] = ex.Exception;
283 Errors [re.Url] = ex;
288 public void ResolveOneLevel ()
290 ArrayList list = new ArrayList (References.Values);
291 foreach (DiscoveryReference re in list)
295 public DiscoveryClientResultCollection WriteAll (string directory, string topLevelFilename)
297 DiscoveryClientResultsFile resfile = new DiscoveryClientResultsFile();
299 foreach (DiscoveryReference re in References.Values)
301 object doc = Documents [re.Url];
302 if (doc == null) continue;
304 string fileName = FindValidName (resfile, re.DefaultFilename);
305 resfile.Results.Add (new DiscoveryClientResult (re.GetType(), re.Url, fileName));
307 string filepath = Path.Combine (directory, fileName);
308 FileStream fs = new FileStream (filepath, FileMode.Create, FileAccess.Write);
309 re.WriteDocument (doc, fs);
313 StreamWriter sw = new StreamWriter (Path.Combine (directory, topLevelFilename));
314 XmlSerializer ser = new XmlSerializer (typeof (DiscoveryClientResultsFile));
315 ser.Serialize (sw, resfile);
317 return resfile.Results;
320 string FindValidName (DiscoveryClientResultsFile resfile, string baseName)
322 string name = baseName;
328 foreach (DiscoveryClientResult res in resfile.Results)
330 if (name == res.Filename) {
335 name = Path.GetFileNameWithoutExtension (baseName) + (++id) + Path.GetExtension (baseName);
342 #endregion // Methods
346 public sealed class DiscoveryClientResultsFile {
350 private DiscoveryClientResultCollection results;
356 public DiscoveryClientResultsFile ()
358 results = new DiscoveryClientResultCollection ();
361 #endregion // Constructors
365 public DiscoveryClientResultCollection Results {
366 get { return results; }
369 #endregion // Properties
372 #endregion // Classes
375 internal class DiscoveryException : Exception
378 public Exception Exception;
380 public DiscoveryException (string url, Exception origin)