de45dfdd88f94cb2fbdb63136def461dabcecf5a
[mono.git] / mcs / class / referencesource / System.Web.Services / System / Web / Services / Discovery / DiscoveryClientProtocol.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="DiscoveryClientProtocol.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Web.Services.Discovery {
8
9     using System.Xml.Serialization;
10     using System.IO;
11     using System;
12     using System.Web.Services;
13     using System.Web.Services.Protocols;
14     using System.Net;
15     using System.Collections;
16     using System.Diagnostics;
17     using System.Web.Services.Configuration;
18     using System.Text;
19     using System.Security.Permissions;
20     using System.Globalization;
21     using System.Threading;
22     using System.Runtime.InteropServices;
23     using System.Web.Services.Diagnostics;
24
25     /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol"]/*' />
26     /// <devdoc>
27     ///    <para>[To be supplied.]</para>
28     /// </devdoc>
29     public class DiscoveryClientProtocol : HttpWebClientProtocol {
30         private DiscoveryClientReferenceCollection references = new DiscoveryClientReferenceCollection();
31         private DiscoveryClientDocumentCollection documents = new DiscoveryClientDocumentCollection();
32         private Hashtable inlinedSchemas = new Hashtable();
33         private ArrayList additionalInformation = new ArrayList();
34         private DiscoveryExceptionDictionary errors = new DiscoveryExceptionDictionary();
35
36         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol.DiscoveryClientProtocol"]/*' />
37         /// <devdoc>
38         ///    <para>[To be supplied.]</para>
39         /// </devdoc>
40         public DiscoveryClientProtocol()
41             : base() {
42         }
43
44         internal DiscoveryClientProtocol(HttpWebClientProtocol protocol) : base(protocol) {
45         }
46
47         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol.AdditionalInformation"]/*' />
48         /// <devdoc>
49         ///    <para>[To be supplied.]</para>
50         /// </devdoc>
51         public IList AdditionalInformation {
52             get {
53                 return additionalInformation;
54             }
55         }
56
57         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol.Documents"]/*' />
58         /// <devdoc>
59         ///    <para>[To be supplied.]</para>
60         /// </devdoc>
61         public DiscoveryClientDocumentCollection Documents {
62             get {
63                 return documents;
64             }
65         }
66
67         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol.Errors"]/*' />
68         /// <devdoc>
69         ///    <para>[To be supplied.]</para>
70         /// </devdoc>
71         public DiscoveryExceptionDictionary Errors {
72             get {
73                 return errors;
74             }
75         }
76
77         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol.References"]/*' />
78         /// <devdoc>
79         ///    <para>[To be supplied.]</para>
80         /// </devdoc>
81         public DiscoveryClientReferenceCollection References {
82             get {
83                 return references;
84             }
85         }
86
87         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol.References"]/*' />
88         /// <devdoc>
89         ///    <para>[To be supplied.]</para>
90         /// </devdoc>
91         internal Hashtable InlinedSchemas
92         {
93             get 
94             {
95                 return inlinedSchemas;
96             }
97         }
98         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol.Discover"]/*' />
99         /// <devdoc>
100         ///    <para>[To be supplied.]</para>
101         /// </devdoc>
102         [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
103         public DiscoveryDocument Discover(string url) {
104             DiscoveryDocument doc = Documents[url] as DiscoveryDocument;
105             if (doc != null)
106                 return doc;
107
108             DiscoveryDocumentReference docRef = new DiscoveryDocumentReference(url);
109             docRef.ClientProtocol = this;
110             References[url] = docRef;
111
112             Errors.Clear();
113             // this will auto-resolve and place the document in the Documents hashtable.
114             return docRef.Document;
115         }
116
117         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol.DiscoverAny"]/*' />
118         /// <devdoc>
119         ///    <para>[To be supplied.]</para>
120         /// </devdoc>
121         [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
122         public DiscoveryDocument DiscoverAny(string url) {
123             Type[] refTypes = WebServicesSection.Current.DiscoveryReferenceTypes;
124             DiscoveryReference discoRef = null;
125             string contentType = null;
126             Stream stream = Download(ref url, ref contentType);
127
128             Errors.Clear();
129             bool allErrorsAreHtmlContentType = true;
130             Exception errorInValidDocument = null;
131             ArrayList specialErrorMessages = new ArrayList();
132             foreach (Type type in refTypes) {
133                 if (!typeof(DiscoveryReference).IsAssignableFrom(type))
134                     continue;
135                 discoRef = (DiscoveryReference) Activator.CreateInstance(type);
136                 discoRef.Url = url;
137                 discoRef.ClientProtocol = this;
138                 stream.Position = 0;
139                 Exception e = discoRef.AttemptResolve(contentType, stream);
140                 if (e == null)
141                     break;
142
143                 Errors[type.FullName] = e;
144                 discoRef = null;
145
146                 InvalidContentTypeException e2 = e as InvalidContentTypeException;
147                 if (e2 == null || !ContentType.MatchesBase(e2.ContentType, "text/html"))
148                     allErrorsAreHtmlContentType = false;
149
150                 InvalidDocumentContentsException e3 = e as InvalidDocumentContentsException;
151                 if (e3 != null) {
152                     errorInValidDocument = e;
153                     break;
154                 }
155
156                 if (e.InnerException != null && e.InnerException.InnerException == null)
157                     specialErrorMessages.Add(e.InnerException.Message);
158             }
159
160             if (discoRef == null) {
161                 if (errorInValidDocument != null) {
162                     StringBuilder errorMessage = new StringBuilder(Res.GetString(Res.TheDocumentWasUnderstoodButContainsErrors));
163                     while (errorInValidDocument != null) {
164                         errorMessage.Append("\n  - ").Append(errorInValidDocument.Message);
165                         errorInValidDocument = errorInValidDocument.InnerException;
166                     }
167                     throw new InvalidOperationException(errorMessage.ToString());
168                 }
169                 else if (allErrorsAreHtmlContentType) {
170                     throw new InvalidOperationException(Res.GetString(Res.TheHTMLDocumentDoesNotContainDiscoveryInformation));
171                 }
172                 else {
173                     bool same = specialErrorMessages.Count == Errors.Count && Errors.Count > 0;
174                     for (int i = 1; same && i < specialErrorMessages.Count; i++) {
175                         if ((string) specialErrorMessages[i - 1] != (string) specialErrorMessages[i])
176                             same = false;
177                     }
178                     if (same)
179                         throw new InvalidOperationException(Res.GetString(Res.TheDocumentWasNotRecognizedAsAKnownDocumentType, specialErrorMessages[0]));
180                     else {
181                         Exception e;
182                         StringBuilder errorMessage = new StringBuilder(Res.GetString(Res.WebMissingResource, url));
183                         foreach (DictionaryEntry entry in Errors) {
184                             e = (Exception)(entry.Value);
185                             string refType = (string)(entry.Key);
186                             if (0 == string.Compare(refType, typeof(ContractReference).FullName, StringComparison.Ordinal)) {
187                                 refType = Res.GetString(Res.WebContractReferenceName);
188                             }
189                             else if (0 == string.Compare(refType, typeof(SchemaReference).FullName, StringComparison.Ordinal)) {
190                                 refType = Res.GetString(Res.WebShemaReferenceName);
191                             }
192                             else if (0 == string.Compare(refType, typeof(DiscoveryDocumentReference).FullName, StringComparison.Ordinal)) {
193                                 refType = Res.GetString(Res.WebDiscoveryDocumentReferenceName);
194                             }
195                             errorMessage.Append("\n- ").Append(Res.GetString(Res.WebDiscoRefReport,
196                                                                refType,
197                                                                e.Message));
198                             while (e.InnerException != null) {
199                                 errorMessage.Append("\n  - ").Append(e.InnerException.Message);
200                                 e = e.InnerException;
201                             }
202                         }
203                         throw new InvalidOperationException(errorMessage.ToString());
204                     }
205                 }
206             }
207
208             if (discoRef is DiscoveryDocumentReference)
209                 return ((DiscoveryDocumentReference) discoRef).Document;
210
211             References[discoRef.Url] = discoRef;
212             DiscoveryDocument doc = new DiscoveryDocument();
213             doc.References.Add(discoRef);
214             return doc;
215         }
216
217         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol.Download"]/*' />
218         /// <devdoc>
219         ///    <para>[To be supplied.]</para>
220         /// </devdoc>
221         [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
222         public Stream Download(ref string url) {
223             string contentType = null;
224             return Download(ref url, ref contentType);
225         }
226
227         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol.Download1"]/*' />
228         /// <devdoc>
229         ///    <para>[To be supplied.]</para>
230         /// </devdoc>
231         [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
232         public Stream Download(ref string url, ref string contentType) {
233             WebRequest request = GetWebRequest(new Uri(url));
234             request.Method = "GET";
235 #if DEBUG // 
236             HttpWebRequest httpRequest = request as HttpWebRequest;
237             if (httpRequest != null) {
238                 httpRequest.Timeout = httpRequest.Timeout * 2;
239             }
240 #endif
241             WebResponse response = null;
242             try {
243                 response = GetWebResponse(request);
244             }
245             catch (Exception e) {
246                 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
247                     throw;
248                 }
249                 throw new WebException(Res.GetString(Res.ThereWasAnErrorDownloading0, url), e);
250             }
251             HttpWebResponse httpResponse = response as HttpWebResponse;
252             if (httpResponse != null) {
253                 if (httpResponse.StatusCode != HttpStatusCode.OK) {
254                     string errorMessage = RequestResponseUtils.CreateResponseExceptionString(httpResponse);
255                     throw new WebException(Res.GetString(Res.ThereWasAnErrorDownloading0, url), new WebException(errorMessage, null, WebExceptionStatus.ProtocolError, response));
256                 }
257             }
258             Stream responseStream = response.GetResponseStream();
259             try {
260                 // Uri.ToString() returns the unescaped version
261                 url = response.ResponseUri.ToString();
262                 contentType = response.ContentType;
263
264                 if (response.ResponseUri.Scheme == Uri.UriSchemeFtp ||
265                     response.ResponseUri.Scheme == Uri.UriSchemeFile) {
266                     int dotIndex = response.ResponseUri.AbsolutePath.LastIndexOf('.');
267                     if (dotIndex != -1) {
268                         switch (response.ResponseUri.AbsolutePath.Substring(dotIndex + 1).ToLower(CultureInfo.InvariantCulture)) {
269                             case "xml":
270                             case "wsdl":
271                             case "xsd":
272                             case "disco":
273                                 contentType = ContentType.TextXml;
274                                 break;
275                             default:
276                                 break;
277                         }
278                     }
279                 }
280
281                 // need to return a buffered stream (one that supports CanSeek)
282                 return RequestResponseUtils.StreamToMemoryStream(responseStream);
283             }
284             finally {
285                 responseStream.Close();
286             }
287         }
288
289         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol.LoadExternals"]/*' />
290         /// <devdoc>
291         ///    <para>[To be supplied.]</para>
292         /// <internalonly/>
293         /// </devdoc>
294         [Obsolete("This method will be removed from a future version. The method call is no longer required for resource discovery", false)]
295         [ComVisible(false)]
296         public void LoadExternals() { }
297
298         internal void FixupReferences() {
299             foreach (DiscoveryReference reference in References.Values) {
300                 reference.LoadExternals(InlinedSchemas);
301             }
302             foreach (string url in InlinedSchemas.Keys) {
303                 Documents.Remove(url);
304             }
305         }
306
307         private static bool IsFilenameInUse(Hashtable filenames, string path) {
308             return filenames[path.ToLower(CultureInfo.InvariantCulture)] != null;
309         }
310
311         private static void AddFilename(Hashtable filenames, string path) {
312             filenames.Add(path.ToLower(CultureInfo.InvariantCulture), path);
313         }
314
315         private static string GetUniqueFilename(Hashtable filenames, string path) {
316             if (IsFilenameInUse(filenames, path)) {
317                 string extension = Path.GetExtension(path);
318                 string allElse = path.Substring(0, path.Length - extension.Length);
319                 int append = 0;
320                 do {
321                     path = allElse + append.ToString(CultureInfo.InvariantCulture) + extension;
322                     append++;
323                 } while (IsFilenameInUse(filenames, path));
324             }
325
326             AddFilename(filenames, path);
327             return path;
328         }
329
330         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol.ReadAll"]/*' />
331         /// <devdoc>
332         ///    <para>[To be supplied.]</para>
333         /// </devdoc>
334         [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
335         public DiscoveryClientResultCollection ReadAll(string topLevelFilename) {
336             XmlSerializer ser = new XmlSerializer(typeof(DiscoveryClientResultsFile));
337             Stream file = File.OpenRead(topLevelFilename);
338             string topLevelPath = Path.GetDirectoryName(topLevelFilename);
339             DiscoveryClientResultsFile results = null;
340             try {
341                 results = (DiscoveryClientResultsFile) ser.Deserialize(file);
342                 for (int i = 0; i < results.Results.Count; i++) {
343                     if (results.Results[i] == null)
344                         throw new InvalidOperationException(Res.GetString(Res.WebNullRef));
345                     string typeName = results.Results[i].ReferenceTypeName;
346                     if (typeName == null || typeName.Length == 0)
347                         throw new InvalidOperationException(Res.GetString(Res.WebRefInvalidAttribute, "referenceType"));
348                     DiscoveryReference reference = (DiscoveryReference) Activator.CreateInstance(Type.GetType(typeName));
349                     reference.ClientProtocol = this;
350
351                     string url = results.Results[i].Url;
352                     if (url == null || url.Length == 0)
353                         throw new InvalidOperationException(Res.GetString(Res.WebRefInvalidAttribute2, reference.GetType().FullName, "url"));
354                     reference.Url = url;
355                     string fileName = results.Results[i].Filename;
356                     if (fileName == null || fileName.Length == 0)
357                         throw new InvalidOperationException(Res.GetString(Res.WebRefInvalidAttribute2, reference.GetType().FullName, "filename"));
358
359                     Stream docFile = File.OpenRead(Path.Combine(topLevelPath, results.Results[i].Filename));
360                     try {
361                         Documents[reference.Url] = reference.ReadDocument(docFile);
362                         Debug.Assert(Documents[reference.Url] != null, "Couldn't deserialize file " + results.Results[i].Filename);
363                     }
364                     finally {
365                         docFile.Close();
366                     }
367                     References[reference.Url] = reference;
368                 }
369                 ResolveAll();
370             }
371             finally {
372                 file.Close();
373             }
374             return results.Results;
375         }
376
377         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol.ResolveAll"]/*' />
378         /// <devdoc>
379         ///    <para>[To be supplied.]</para>
380         /// </devdoc>
381         [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
382         public void ResolveAll() {
383             // Resolve until we reach a 'steady state' (no more references added)
384             Errors.Clear();
385             int resolvedCount = InlinedSchemas.Keys.Count;
386             while (resolvedCount != References.Count) {
387                 resolvedCount = References.Count;
388                 DiscoveryReference[] refs = new DiscoveryReference[References.Count];
389                 References.Values.CopyTo(refs, 0);
390                 for (int i = 0; i < refs.Length; i++) {
391                     DiscoveryReference discoRef = refs[i];
392                     if (discoRef is DiscoveryDocumentReference) {
393                         try {
394                             // Resolve discovery document references deeply
395                             ((DiscoveryDocumentReference)discoRef).ResolveAll(true);
396                         }
397                         catch (Exception e) {
398                             if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
399                                 throw;
400                             }
401                             // don't let the exception out - keep going. Just add it to the list of errors.
402                             Errors[discoRef.Url] = e;
403                             if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Warning, this, "ResolveAll", e);
404                         }
405                     }
406                     else {
407                         try {
408                             discoRef.Resolve();
409                         }
410                         catch (Exception e) {
411                             if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
412                                 throw;
413                             }
414                             // don't let the exception out - keep going. Just add it to the list of errors.
415                             Errors[discoRef.Url] = e;
416                             if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Warning, this, "ResolveAll", e);
417                         }
418                     }
419                 }
420             }
421             FixupReferences();
422         }
423
424         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol.ResolveOneLevel"]/*' />
425         /// <devdoc>
426         ///    <para>[To be supplied.]</para>
427         /// </devdoc>
428         [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
429         public void ResolveOneLevel() {
430             // download everything we have a reference to, but don't recurse.
431             Errors.Clear();
432             DiscoveryReference[] refs = new DiscoveryReference[References.Count];
433             References.Values.CopyTo(refs, 0);
434             for (int i = 0; i < refs.Length; i++) {
435                 try {
436                     refs[i].Resolve();
437                 }
438                 catch (Exception e) {
439                     if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
440                         throw;
441                     }
442                     // don't let the exception out - keep going. Just add it to the list of errors.
443                     Errors[refs[i].Url] = e;
444                     if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Warning, this, "ResolveOneLevel", e);
445                 }
446             }
447         }
448
449         private static string GetRelativePath(string fullPath, string relativeTo) {
450             string currentDir = Path.GetDirectoryName(Path.GetFullPath(relativeTo));
451
452             string answer = "";
453             while (currentDir.Length > 0) {
454                 if (currentDir.Length <= fullPath.Length && string.Compare(currentDir, fullPath.Substring(0, currentDir.Length), StringComparison.OrdinalIgnoreCase) == 0) {
455                     answer += fullPath.Substring(currentDir.Length);
456                     if (answer.StartsWith("\\", StringComparison.Ordinal))
457                         answer = answer.Substring(1);
458                     return answer;
459                 }
460                 answer += "..\\";
461                 if (currentDir.Length < 2)
462                     break;
463                 else {
464                     int lastSlash = currentDir.LastIndexOf('\\', currentDir.Length - 2);
465                     currentDir = currentDir.Substring(0, lastSlash + 1);
466                 }
467             }
468             return fullPath;
469         }
470
471         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol.WriteAll"]/*' />
472         /// <devdoc>
473         ///    <para>[To be supplied.]</para>
474         /// </devdoc>
475         [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
476         public DiscoveryClientResultCollection WriteAll(string directory, string topLevelFilename) {
477             DiscoveryClientResultsFile results = new DiscoveryClientResultsFile();
478             Hashtable filenames = new Hashtable();
479             string topLevelFullPath = Path.Combine(directory, topLevelFilename);
480
481             // write out each of the documents
482             DictionaryEntry[] entries = new DictionaryEntry[Documents.Count + InlinedSchemas.Keys.Count];
483             int i = 0;
484             foreach (DictionaryEntry entry in Documents) {
485                 entries[i++] = entry;
486             }
487             foreach (DictionaryEntry entry in InlinedSchemas) {
488                 entries[i++] = entry;
489             }
490             foreach (DictionaryEntry entry in entries) {
491                 string url = (string) entry.Key;
492                 object document = entry.Value;
493                 if (document == null)
494                     continue;
495                 DiscoveryReference reference = References[url];
496                 string filename = reference == null ? DiscoveryReference.FilenameFromUrl(Url) : reference.DefaultFilename;
497                 filename = GetUniqueFilename(filenames, Path.GetFullPath(Path.Combine(directory, filename)));
498                 results.Results.Add(new DiscoveryClientResult(reference == null ? null : reference.GetType(), url, GetRelativePath(filename, topLevelFullPath)));
499                 Stream file = File.Create(filename);
500                 try {
501                     reference.WriteDocument(document, file);
502                 }
503                 finally {
504                     file.Close();
505                 }
506             }
507
508             // write out the file that points to all those documents.
509             XmlSerializer ser = new XmlSerializer(typeof(DiscoveryClientResultsFile));
510             Stream topLevelFile = File.Create(topLevelFullPath);
511             try {
512                 ser.Serialize(new StreamWriter(topLevelFile, new UTF8Encoding(false)), results);
513             }
514             finally {
515                 topLevelFile.Close();
516             }
517
518             return results.Results;
519         }
520
521         // 
522
523
524
525
526
527         public sealed class DiscoveryClientResultsFile {
528             private DiscoveryClientResultCollection results = new DiscoveryClientResultCollection();
529             /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientProtocol.DiscoveryClientResultsFile.Results"]/*' />
530             /// <devdoc>
531             ///    <para>[To be supplied.]</para>
532             /// </devdoc>
533             public DiscoveryClientResultCollection Results {
534                 get {
535                     return results;
536                 }
537             }
538         }
539
540     }
541
542     /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientResultCollection"]/*' />
543     /// <devdoc>
544     ///    <para>[To be supplied.]</para>
545     /// </devdoc>
546     public sealed class DiscoveryClientResultCollection : CollectionBase {
547
548         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientResultCollection.this"]/*' />
549         /// <devdoc>
550         ///    <para>[To be supplied.]</para>
551         /// </devdoc>
552         public DiscoveryClientResult this[int i] {
553             get {
554                 return (DiscoveryClientResult) List[i];
555             }
556             set {
557                 List[i] = value;
558             }
559         }
560
561         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientResultCollection.Add"]/*' />
562         /// <devdoc>
563         ///    <para>[To be supplied.]</para>
564         /// </devdoc>
565         public int Add(DiscoveryClientResult value) {
566             return List.Add(value);
567         }
568
569         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientResultCollection.Contains"]/*' />
570         /// <devdoc>
571         ///    <para>[To be supplied.]</para>
572         /// </devdoc>
573         public bool Contains(DiscoveryClientResult value) {
574             return List.Contains(value);
575         }
576
577         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientResultCollection.Remove"]/*' />
578         /// <devdoc>
579         ///    <para>[To be supplied.]</para>
580         /// </devdoc>
581         public void Remove(DiscoveryClientResult value) {
582             List.Remove(value);
583         }
584
585     }
586
587     /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientResult"]/*' />
588     /// <devdoc>
589     ///    <para>[To be supplied.]</para>
590     /// </devdoc>
591     public sealed class DiscoveryClientResult {
592         string referenceTypeName;
593         string url;
594         string filename;
595
596         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientResult.DiscoveryClientResult"]/*' />
597         /// <devdoc>
598         ///    <para>[To be supplied.]</para>
599         /// </devdoc>
600         public DiscoveryClientResult() {
601         }
602
603         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientResult.DiscoveryClientResult1"]/*' />
604         /// <devdoc>
605         ///    <para>[To be supplied.]</para>
606         /// </devdoc>
607         public DiscoveryClientResult(Type referenceType, string url, string filename) {
608             this.referenceTypeName = referenceType == null ? string.Empty : referenceType.FullName;
609             this.url = url;
610             this.filename = filename;
611         }
612
613         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientResult.ReferenceTypeName"]/*' />
614         /// <devdoc>
615         ///    <para>[To be supplied.]</para>
616         /// </devdoc>
617         [XmlAttribute("referenceType")]
618         public string ReferenceTypeName {
619             get {
620                 return referenceTypeName;
621             }
622             set {
623                 referenceTypeName = value;
624             }
625         }
626
627         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientResult.Url"]/*' />
628         /// <devdoc>
629         ///    <para>[To be supplied.]</para>
630         /// </devdoc>
631         [XmlAttribute("url")]
632         public string Url {
633             get {
634                 return url;
635             }
636             set {
637                 url = value;
638             }
639         }
640
641         /// <include file='doc\DiscoveryClientProtocol.uex' path='docs/doc[@for="DiscoveryClientResult.Filename"]/*' />
642         /// <devdoc>
643         ///    <para>[To be supplied.]</para>
644         /// </devdoc>
645         [XmlAttribute("filename")]
646         public string Filename {
647             get {
648                 return filename;
649             }
650             set {
651                 filename = value;
652             }
653         }
654     }
655 }