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