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")]
MetadataExchangeClient()61 		public MetadataExchangeClient ()
62 		{
63 		}
64 
MetadataExchangeClient(SMBinding mexBinding)65 		public MetadataExchangeClient (SMBinding mexBinding)
66 		{
67 			binding = mexBinding;
68 		}
69 
MetadataExchangeClient(EndpointAddress address)70 		public MetadataExchangeClient (EndpointAddress address)
71 		{
72 			this.address = address;
73 		}
74 
MetadataExchangeClient(string endpointConfigurationName)75 		public MetadataExchangeClient (string endpointConfigurationName)
76 		{
77 			throw new NotImplementedException ();
78 		}
79 
80 		[MonoTODO ("MetadataExchangeClientMode is not considered")]
MetadataExchangeClient(Uri address, MetadataExchangeClientMode mode)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?)")]
GetChannelFactory(EndpointAddress metadataAddress, string dialect, string identifier)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]
GetWebRequest(Uri location, string dialect, string identifier)124 		protected internal virtual HttpWebRequest GetWebRequest (Uri location, string dialect, string identifier)
125 		{
126 			throw new NotImplementedException ();
127 		}
128 
CreateBinding(EndpointAddress address)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 
GetMetadata()138 		public MetadataSet GetMetadata ()
139 		{
140 			return GetMetadata (address);
141 		}
142 
GetMetadata(EndpointAddress address)143 		public MetadataSet GetMetadata (EndpointAddress address)
144 		{
145 			//FIXME: default mode?
146 			return GetMetadataInternal (address, mode);
147 		}
148 
GetMetadata(Uri address, MetadataExchangeClientMode mode)149 		public MetadataSet GetMetadata (Uri address, MetadataExchangeClientMode mode)
150 		{
151 			return GetMetadataInternal (new EndpointAddress (address.AbsoluteUri), mode);
152 		}
153 
GetMetadataInternal(EndpointAddress address, MetadataExchangeClientMode mode)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 
PrepareGetter()191 		void PrepareGetter ()
192 		{
193 			if (getter == null)
194 				getter = new Func<Func<MetadataSet>,MetadataSet> (GetMetadata);
195 		}
196 
EndGetMetadata(IAsyncResult result)197 		public MetadataSet EndGetMetadata (IAsyncResult result)
198 		{
199 			return getter.EndInvoke (result);
200 		}
201 
GetMetadata(Func<MetadataSet> func)202 		MetadataSet GetMetadata (Func<MetadataSet> func)
203 		{
204 			return func ();
205 		}
206 
BeginGetMetadata(AsyncCallback callback, object asyncState)207 		public IAsyncResult BeginGetMetadata (AsyncCallback callback, object asyncState)
208 		{
209 			PrepareGetter ();
210 			return getter.BeginInvoke (() => GetMetadata (), callback, asyncState);
211 		}
212 
BeginGetMetadata(EndpointAddress address, AsyncCallback callback, object asyncState)213 		public IAsyncResult BeginGetMetadata (EndpointAddress address, AsyncCallback callback, object asyncState)
214 		{
215 			PrepareGetter ();
216 			return getter.BeginInvoke (() => GetMetadata (address), callback, asyncState);
217 		}
218 
BeginGetMetadata(Uri address, MetadataExchangeClientMode mode, AsyncCallback callback, object asyncState)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 }
230