1 //------------------------------------------------------------------------------
2 // <copyright file="DiscoveryDocumentReference.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
7 namespace System
.Web
.Services
.Discovery
{
12 using System
.Diagnostics
;
14 using System
.Xml
.Serialization
;
15 using System
.Web
.Services
.Protocols
;
16 using System
.Web
.Services
.Configuration
;
18 using System
.Globalization
;
19 using System
.Threading
;
20 using System
.Collections
;
21 using System
.Web
.Services
.Diagnostics
;
23 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference"]/*' />
25 /// <para>[To be supplied.]</para>
27 [XmlRoot("discoveryRef", Namespace
= DiscoveryDocument
.Namespace
)]
28 public sealed class DiscoveryDocumentReference
: DiscoveryReference
{
30 private string reference
;
32 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.DiscoveryDocumentReference"]/*' />
34 /// <para>[To be supplied.]</para>
36 public DiscoveryDocumentReference() {
39 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.DiscoveryDocumentReference1"]/*' />
41 /// <para>[To be supplied.]</para>
43 public DiscoveryDocumentReference(string href
) {
47 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.Ref"]/*' />
49 /// <para>[To be supplied.]</para>
54 return reference
== null ? "" : reference
;
61 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.DefaultFilename"]/*' />
63 /// <para>[To be supplied.]</para>
66 public override string DefaultFilename
{
68 string filename
= FilenameFromUrl(Url
);
69 return Path
.ChangeExtension(filename
, ".disco"); // [Microsoft] change default extension
73 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.Document"]/*' />
75 /// <para>[To be supplied.]</para>
78 public DiscoveryDocument Document
{
80 if (ClientProtocol
== null)
81 throw new InvalidOperationException(Res
.GetString(Res
.WebMissingClientProtocol
));
82 object document
= ClientProtocol
.Documents
[Url
];
83 if (document
== null) {
85 document
= ClientProtocol
.Documents
[Url
];
87 DiscoveryDocument discoDocument
= document
as DiscoveryDocument
;
88 if (discoDocument
== null) {
89 throw new InvalidOperationException(Res
.GetString(Res
.WebInvalidDocType
,
90 typeof(DiscoveryDocument
).FullName
,
91 document
== null ? string.Empty
: document
.GetType().FullName
,
98 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.WriteDocument"]/*' />
100 /// <para>[To be supplied.]</para>
102 public override void WriteDocument(object document
, Stream stream
) {
103 WebServicesSection
.Current
.DiscoveryDocumentSerializer
.Serialize(new StreamWriter(stream
, new UTF8Encoding(false)), document
);
106 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.ReadDocument"]/*' />
108 /// <para>[To be supplied.]</para>
110 public override object ReadDocument(Stream stream
) {
111 return WebServicesSection
.Current
.DiscoveryDocumentSerializer
.Deserialize(stream
);
114 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.Url"]/*' />
116 /// <para>[To be supplied.]</para>
119 public override string Url
{
124 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.GetDocumentNoParse"]/*' />
126 /// Retrieves a discovery document from Url, either out of the ClientProtocol
127 /// or from a stream. Does not
129 private static DiscoveryDocument
GetDocumentNoParse(ref string url
, DiscoveryClientProtocol client
) {
130 DiscoveryDocument d
= (DiscoveryDocument
) client
.Documents
[url
];
135 string contentType
= null;
137 Stream stream
= client
.Download(ref url
, ref contentType
);
139 XmlTextReader reader
= new XmlTextReader(new StreamReader(stream
, RequestResponseUtils
.GetEncoding(contentType
)));
140 reader
.WhitespaceHandling
= WhitespaceHandling
.Significant
;
141 reader
.XmlResolver
= null;
142 reader
.DtdProcessing
= DtdProcessing
.Prohibit
;
143 if (!DiscoveryDocument
.CanRead(reader
)) {
144 // there is no discovery document at this location
145 ArgumentException exception
= new ArgumentException(Res
.GetString(Res
.WebInvalidFormat
));
146 throw new InvalidOperationException(Res
.GetString(Res
.WebMissingDocument
, url
), exception
);
148 return DiscoveryDocument
.Read(reader
);
155 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.Resolve"]/*' />
157 /// <para>[To be supplied.]</para>
159 protected internal override void Resolve(string contentType
, Stream stream
) {
160 DiscoveryDocument document
= null;
162 if (ContentType
.IsHtml(contentType
)) {
163 string newRef
= LinkGrep
.SearchForLink(stream
);
164 if (newRef
!= null) {
165 string newUrl
= UriToString(Url
, newRef
);
166 document
= GetDocumentNoParse(ref newUrl
, ClientProtocol
);
170 throw new InvalidContentTypeException(Res
.GetString(Res
.WebInvalidContentType
, contentType
), contentType
);
173 if (document
== null) { // probably xml...
174 XmlTextReader reader
= new XmlTextReader(new StreamReader(stream
, RequestResponseUtils
.GetEncoding(contentType
)));
175 reader
.XmlResolver
= null;
176 reader
.WhitespaceHandling
= WhitespaceHandling
.Significant
;
177 reader
.DtdProcessing
= DtdProcessing
.Prohibit
;
178 if (DiscoveryDocument
.CanRead(reader
)) {
179 // it's a discovery document, so just read it.
180 document
= DiscoveryDocument
.Read(reader
);
183 // check out the processing instructions before the first tag. if any of them
184 // match the form specified in the DISCO spec, save the href.
186 XmlTextReader newReader
= new XmlTextReader(new StreamReader(stream
, RequestResponseUtils
.GetEncoding(contentType
)));
187 newReader
.XmlResolver
= null;
188 newReader
.DtdProcessing
= DtdProcessing
.Prohibit
;
189 while (newReader
.NodeType
!= XmlNodeType
.Element
) {
190 if (newReader
.NodeType
== XmlNodeType
.ProcessingInstruction
) {
191 // manually parse the PI contents since XmlTextReader won't automatically do it
192 StringBuilder sb
= new StringBuilder("<pi ");
193 sb
.Append(newReader
.Value
);
195 XmlTextReader piReader
= new XmlTextReader(new StringReader(sb
.ToString()));
196 piReader
.XmlResolver
= null;
197 piReader
.DtdProcessing
= DtdProcessing
.Prohibit
;
199 string type
= piReader
["type"];
200 string alternate
= piReader
["alternate"];
201 string href
= piReader
["href"];
202 if (type
!= null && ContentType
.MatchesBase(type
, ContentType
.TextXml
)
203 && alternate
!= null && string.Compare(alternate
, "yes", StringComparison
.OrdinalIgnoreCase
) == 0
205 // we got a PI with the right attributes
207 // there is a link to a discovery document. follow it after fully qualifying it.
208 string newUrl
= UriToString(Url
, href
);
209 document
= GetDocumentNoParse(ref newUrl
, ClientProtocol
);
219 if (document
== null) {
220 // there is no discovery document at this location
222 if (ContentType
.IsXml(contentType
)) {
223 exception
= new ArgumentException(Res
.GetString(Res
.WebInvalidFormat
));
226 exception
= new InvalidContentTypeException(Res
.GetString(Res
.WebInvalidContentType
, contentType
), contentType
);
228 throw new InvalidOperationException(Res
.GetString(Res
.WebMissingDocument
, Url
), exception
);
231 ClientProtocol
.References
[Url
] = this;
232 ClientProtocol
.Documents
[Url
] = document
;
234 foreach (object o
in document
.References
) {
235 if (o
is DiscoveryReference
) {
236 DiscoveryReference r
= (DiscoveryReference
) o
;
237 if (r
.Url
.Length
== 0) {
238 throw new InvalidOperationException(Res
.GetString(Res
.WebEmptyRef
, r
.GetType().FullName
, Url
));
240 r
.Url
= UriToString(Url
, r
.Url
);
241 //All inheritors of DiscoveryReference that got URIs relative
242 //to Ref property should adjust them like ContractReference does here.
243 ContractReference cr
= r
as ContractReference
;
244 if ( (cr
!= null) && (cr
.DocRef
!= null) ) {
245 cr
.DocRef
= UriToString(Url
, cr
.DocRef
);
247 r
.ClientProtocol
= ClientProtocol
;
248 ClientProtocol
.References
[r
.Url
] = r
;
251 ClientProtocol
.AdditionalInformation
.Add(o
);
257 /// <include file='doc\DiscoveryDocumentReference.uex' path='docs/doc[@for="DiscoveryDocumentReference.ResolveAll"]/*' />
259 /// <para>[To be supplied.]</para>
261 public void ResolveAll() {
265 internal void ResolveAll(bool throwOnError
) {
269 catch (Exception e
) {
270 if (e
is ThreadAbortException
|| e
is StackOverflowException
|| e
is OutOfMemoryException
) {
276 if (Tracing
.On
) Tracing
.ExceptionCatch(TraceEventType
.Warning
, this, "ResolveAll", e
);
278 // can't continue, because we couldn't find a document.
282 foreach (object o
in Document
.References
) {
283 DiscoveryDocumentReference r
= o
as DiscoveryDocumentReference
;
286 if (ClientProtocol
.Documents
[r
.Url
] != null) {
289 r
.ClientProtocol
= ClientProtocol
;
290 r
.ResolveAll(throwOnError
);