Merge pull request #1656 from alexanderkyte/webservice_27561
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel.Description / MetadataExchangeClient.cs
1 //
2 // MetadataExchangeClient.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //      Ankit Jain <jankit@novell.com>
7 //
8 // Copyright (C) 2005 Novell, Inc.  http://www.novell.com
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29 using System;
30 using System.Collections.Generic;
31 using System.Collections.ObjectModel;
32 using System.ServiceModel;
33 using System.ServiceModel.Channels;
34 using System.ServiceModel.Description;
35 using System.Web.Services.Description;
36 using System.Web.Services.Discovery;
37 using System.Web.Services.Protocols;
38 using System.Xml;
39 using System.Xml.Serialization;
40 using System.IO;
41 using System.Net;
42 using System.Text;
43
44 using SMBinding = System.ServiceModel.Channels.Binding;
45 using SMMessage = System.ServiceModel.Channels.Message;
46
47 namespace System.ServiceModel.Description
48 {
49         public class MetadataExchangeClient
50         {
51                 string scheme;
52
53                 EndpointAddress address;
54                 SMBinding binding;
55                 MetadataExchangeClientMode mode = MetadataExchangeClientMode.MetadataExchange;
56                 TimeSpan? operation_timeout = null;
57
58                 // constructors
59
60                 [MonoTODO ("use empty configuration")]
61                 public MetadataExchangeClient ()
62                 {
63                 }
64
65                 public MetadataExchangeClient (SMBinding mexBinding)
66                 {
67                         binding = mexBinding;
68                 }
69
70                 public MetadataExchangeClient (EndpointAddress address)
71                 {
72                         this.address = address;
73                 }
74
75                 public MetadataExchangeClient (string endpointConfigurationName)
76                 {
77                         throw new NotImplementedException ();
78                 }
79
80                 [MonoTODO ("MetadataExchangeClientMode is not considered")]
81                 public MetadataExchangeClient (Uri address, MetadataExchangeClientMode mode)
82                 {
83                         this.address = new EndpointAddress (address.AbsoluteUri);
84                         this.mode = mode;
85                 }
86
87                 [MonoTODO]
88                 public ICredentials HttpCredentials { get; set; }
89                 [MonoTODO]
90                 public int MaximumResolvedReferences { get; set; }
91
92                 public TimeSpan OperationTimeout {
93                         get {
94                                 if (!this.operation_timeout.HasValue) {
95                                         this.operation_timeout = DefaultCommunicationTimeouts.Instance.ReceiveTimeout;
96                                 }
97                                 return this.operation_timeout.Value;
98                         }
99                         set {
100                                 this.operation_timeout = value;
101                         }
102                 }
103
104                 [MonoTODO]
105                 public bool ResolveMetadataReferences { get; set; }
106
107                 public ClientCredentials SoapCredentials { get; set; }
108
109                 [MonoTODO ("use dialect and identifier (but how?)")]
110                 protected internal virtual ChannelFactory<IMetadataExchange> GetChannelFactory (EndpointAddress metadataAddress, string dialect, string identifier)
111                 {
112                         if (metadataAddress == null)
113                                 throw new ArgumentNullException ("metadataAddress");
114
115                         var se = new ServiceEndpoint (ContractDescription.GetContract (typeof (IMetadataExchange)), CreateBinding (metadataAddress), metadataAddress);
116                         if (SoapCredentials != null) {
117                                 se.Behaviors.RemoveAll<ClientCredentials> ();
118                                 se.Behaviors.Add (SoapCredentials);
119                         }
120                         return new ChannelFactory<IMetadataExchange> (se);
121                 }
122
123                 [MonoTODO]
124                 protected internal virtual HttpWebRequest GetWebRequest (Uri location, string dialect, string identifier)
125                 {
126                         throw new NotImplementedException ();
127                 }
128
129                 SMBinding CreateBinding (EndpointAddress address)
130                 {
131                         return address.Uri.Scheme == Uri.UriSchemeHttps ?
132                                 MetadataExchangeBindings.CreateMexHttpsBinding () :
133                                 MetadataExchangeBindings.CreateMexHttpBinding ();
134                 }
135
136                 // sync methods
137
138                 public MetadataSet GetMetadata ()
139                 {
140                         return GetMetadata (address);
141                 }
142
143                 public MetadataSet GetMetadata (EndpointAddress address)
144                 {
145                         //FIXME: default mode?
146                         return GetMetadataInternal (address, mode);
147                 }
148
149                 public MetadataSet GetMetadata (Uri address, MetadataExchangeClientMode mode)
150                 {
151                         return GetMetadataInternal (new EndpointAddress (address.AbsoluteUri), mode);
152                 }
153
154                 internal MetadataSet GetMetadataInternal (EndpointAddress address, MetadataExchangeClientMode mode)
155                 {
156                         // FIXME: give dialect and identifier
157                         var cf = GetChannelFactory (address, null, null);
158                         cf.Open ();
159                         var proxy = cf.CreateChannel ();
160                         var asClientChannel = proxy as IClientChannel;
161                         if (asClientChannel == null)
162                                 throw new InvalidOperationException ("The channel factory must return an IClientChannel implementation");
163                         asClientChannel.OperationTimeout = OperationTimeout;
164                         asClientChannel.Open ();
165
166                         SMMessage msg = SMMessage.CreateMessage ( 
167                                         MessageVersion.Soap12WSAddressing10, 
168                                         "http://schemas.xmlsoap.org/ws/2004/09/transfer/Get");
169
170                         msg.Headers.ReplyTo = new EndpointAddress (
171                                         "http://www.w3.org/2005/08/addressing/anonymous");
172                         //msg.Headers.From = new EndpointAddress ("http://localhost");
173                         msg.Headers.To = address.Uri;
174                         msg.Headers.MessageId = new UniqueId ();
175
176                         SMMessage ret;
177                         try {
178                                 ret = proxy.Get (msg);
179                         } catch (Exception e) {
180                                 throw new InvalidOperationException (
181                                                 "Metadata contains a reference that cannot be resolved : " + address.Uri.AbsoluteUri, e);
182                         }
183
184                         return MetadataSet.ReadFrom (ret.GetReaderAtBodyContents ());
185                 }
186
187                 // async methods
188
189                 Func<Func<MetadataSet>,MetadataSet> getter;
190
191                 void PrepareGetter ()
192                 {
193                         if (getter == null)
194                                 getter = new Func<Func<MetadataSet>,MetadataSet> (GetMetadata);
195                 }
196
197                 public MetadataSet EndGetMetadata (IAsyncResult result)
198                 {
199                         return getter.EndInvoke (result);
200                 }
201
202                 MetadataSet GetMetadata (Func<MetadataSet> func)
203                 {
204                         return func ();
205                 }
206
207                 public IAsyncResult BeginGetMetadata (AsyncCallback callback, object asyncState)
208                 {
209                         PrepareGetter ();
210                         return getter.BeginInvoke (() => GetMetadata (), callback, asyncState);
211                 }
212
213                 public IAsyncResult BeginGetMetadata (EndpointAddress address, AsyncCallback callback, object asyncState)
214                 {
215                         PrepareGetter ();
216                         return getter.BeginInvoke (() => GetMetadata (address), callback, asyncState);
217                 }
218
219                 public IAsyncResult BeginGetMetadata (Uri address, MetadataExchangeClientMode mode, AsyncCallback callback, object asyncState)
220                 {
221                         PrepareGetter ();
222                         return getter.BeginInvoke (() => GetMetadata (address, mode), callback, asyncState);
223                 }
224         }
225
226         interface IMetadataExchangeClient : IMetadataExchange, IClientChannel
227         {
228         }
229 }