1 //----------------------------------------------------------------------------- 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //----------------------------------------------------------------------------- 4 #pragma warning disable 1634, 1691 5 6 namespace System.ServiceModel.ComIntegration 7 { 8 using System; 9 using System.Collections.Generic; 10 using System.Diagnostics; 11 using System.Runtime; 12 using System.Runtime.InteropServices; 13 using System.Runtime.Remoting; 14 using System.Runtime.Remoting.Proxies; 15 using System.ServiceModel; 16 using System.ServiceModel.Channels; 17 using System.ServiceModel.Description; 18 using System.ServiceModel.Diagnostics; 19 using System.Threading; 20 21 class TypedServiceChannelBuilder : IProxyCreator, IProvideChannelBuilderSettings, ICreateServiceChannel 22 { 23 24 ServiceChannelFactory serviceChannelFactory = null; 25 Type contractType = null; 26 27 // Double-checked locking pattern requires volatile for read/write synchronization 28 volatile RealProxy serviceProxy = null; 29 ServiceEndpoint serviceEndpoint = null; 30 KeyedByTypeCollection<IEndpointBehavior> behaviors = new KeyedByTypeCollection<IEndpointBehavior>(); 31 Binding binding = null; 32 string configurationName = null; 33 string address = null; 34 EndpointIdentity identity = null; 35 IDisposable.Dispose()36 void IDisposable.Dispose() 37 { 38 if (serviceProxy != null) 39 { 40 IChannel channel = serviceProxy.GetTransparentProxy() as IChannel; 41 if (channel == null) 42 { 43 throw Fx.AssertAndThrow("serviceProxy MUST support IChannel"); 44 } 45 channel.Close(); 46 } 47 } 48 49 //Suppressing PreSharp warning that property get methods should not throw 50 #pragma warning disable 6503 51 ServiceChannelFactory IProvideChannelBuilderSettings.ServiceChannelFactoryReadWrite 52 { 53 get 54 { 55 if (serviceProxy != null) 56 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.TooLate), HR.RPC_E_TOO_LATE)); 57 return serviceChannelFactory; 58 } 59 } 60 #pragma warning restore 6503 61 ServiceChannelFactory IProvideChannelBuilderSettings.ServiceChannelFactoryReadOnly 62 { 63 get 64 { 65 return serviceChannelFactory; 66 } 67 } 68 //Suppressing PreSharp warning that property get methods should not throw 69 #pragma warning disable 6503 70 KeyedByTypeCollection<IEndpointBehavior> IProvideChannelBuilderSettings.Behaviors 71 { 72 get 73 { 74 if (serviceProxy != null) 75 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new COMException(SR.GetString(SR.TooLate), HR.RPC_E_TOO_LATE)); 76 return behaviors; 77 } 78 } 79 #pragma warning restore 6503 80 81 ServiceChannel IProvideChannelBuilderSettings.ServiceChannel 82 { 83 get 84 { 85 return null; 86 } 87 } 88 ICreateServiceChannel.CreateChannel()89 RealProxy ICreateServiceChannel.CreateChannel() 90 { 91 if (serviceProxy == null) 92 { 93 lock (this) 94 { 95 if (serviceProxy == null) 96 { 97 try 98 { 99 if (serviceChannelFactory == null) 100 { 101 FaultInserviceChannelFactory(); 102 } 103 104 if (serviceChannelFactory == null) 105 { 106 throw Fx.AssertAndThrow("ServiceChannelFactory cannot be null at this point"); 107 } 108 109 serviceChannelFactory.Open(); 110 111 if (contractType == null) 112 { 113 throw Fx.AssertAndThrow("contractType cannot be null"); 114 } 115 if (serviceEndpoint == null) 116 { 117 throw Fx.AssertAndThrow("serviceEndpoint cannot be null"); 118 } 119 120 object transparentProxy = serviceChannelFactory.CreateChannel(contractType, new EndpointAddress(serviceEndpoint.Address.Uri, serviceEndpoint.Address.Identity, serviceEndpoint.Address.Headers), serviceEndpoint.Address.Uri); 121 122 ComPlusChannelCreatedTrace.Trace(TraceEventType.Verbose, TraceCode.ComIntegrationChannelCreated, 123 SR.TraceCodeComIntegrationChannelCreated, serviceEndpoint.Address.Uri, contractType); 124 125 RealProxy localProxy = RemotingServices.GetRealProxy(transparentProxy); 126 127 serviceProxy = localProxy; 128 129 if (serviceProxy == null) 130 { 131 throw Fx.AssertAndThrow("serviceProxy MUST derive from RealProxy"); 132 } 133 } 134 finally 135 { 136 if ((serviceProxy == null) && (serviceChannelFactory != null)) 137 serviceChannelFactory.Close(); 138 } 139 } 140 } 141 } 142 return serviceProxy; 143 } 144 CreateServiceEndpoint()145 private ServiceEndpoint CreateServiceEndpoint() 146 { 147 TypeLoader loader = new TypeLoader(); 148 ContractDescription contractDescription = loader.LoadContractDescription(contractType); 149 150 ServiceEndpoint endpoint = new ServiceEndpoint(contractDescription); 151 if (address != null) 152 endpoint.Address = new EndpointAddress(new Uri(address), identity); 153 if (binding != null) 154 endpoint.Binding = binding; 155 156 if (configurationName != null) 157 { 158 ConfigLoader configLoader = new ConfigLoader(); 159 configLoader.LoadChannelBehaviors(endpoint, configurationName); 160 } 161 162 ComPlusTypedChannelBuilderTrace.Trace(TraceEventType.Verbose, TraceCode.ComIntegrationTypedChannelBuilderLoaded, 163 SR.TraceCodeComIntegrationTypedChannelBuilderLoaded, contractType, binding); 164 165 return endpoint; 166 } 167 CreateServiceChannelFactory()168 private ServiceChannelFactory CreateServiceChannelFactory() 169 { 170 ServiceChannelFactory serviceChannelFactory = ServiceChannelFactory.BuildChannelFactory(serviceEndpoint) as ServiceChannelFactory; 171 if (serviceChannelFactory == null) 172 { 173 throw Fx.AssertAndThrow("We should get a ServiceChannelFactory back"); 174 } 175 return serviceChannelFactory; 176 } 177 FaultInserviceChannelFactory()178 void FaultInserviceChannelFactory() 179 { 180 if (contractType == null) 181 { 182 throw Fx.AssertAndThrow("contractType should not be null"); 183 } 184 if (serviceEndpoint == null) 185 { 186 serviceEndpoint = CreateServiceEndpoint(); 187 } 188 foreach (IEndpointBehavior behavior in behaviors) 189 serviceEndpoint.Behaviors.Add(behavior); 190 serviceChannelFactory = CreateServiceChannelFactory(); 191 192 } 193 ResolveTypeIfPossible(Dictionary<MonikerHelper.MonikerAttribute, string> propertyTable)194 internal void ResolveTypeIfPossible(Dictionary<MonikerHelper.MonikerAttribute, string> propertyTable) 195 { 196 string typeIID; 197 propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.Contract, out typeIID); 198 Guid iid; 199 if (!string.IsNullOrEmpty(typeIID)) 200 { 201 try 202 { 203 dispatchEnabled = true; 204 iid = new Guid(typeIID); 205 TypeCacheManager.Provider.FindOrCreateType(iid, out contractType, true, false); 206 serviceEndpoint = CreateServiceEndpoint(); 207 } 208 catch (Exception e) 209 { 210 if (Fx.IsFatal(e)) 211 throw; 212 213 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MonikerSyntaxException(SR.GetString(SR.TypeLoadForContractTypeIIDFailedWith, typeIID, e.Message))); 214 } 215 216 } 217 } 218 TypedServiceChannelBuilder(Dictionary<MonikerHelper.MonikerAttribute, string> propertyTable)219 internal TypedServiceChannelBuilder(Dictionary<MonikerHelper.MonikerAttribute, string> propertyTable) 220 { 221 string bindingType = null; 222 string bindingConfigName = null; 223 224 string spnIdentity = null; 225 string upnIdentity = null; 226 string dnsIdentity = null; 227 228 propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.Address, out address); 229 propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.Binding, out bindingType); 230 propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.BindingConfiguration, out bindingConfigName); 231 propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.SpnIdentity, out spnIdentity); 232 propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.UpnIdentity, out upnIdentity); 233 propertyTable.TryGetValue(MonikerHelper.MonikerAttribute.DnsIdentity, out dnsIdentity); 234 235 if (!string.IsNullOrEmpty(bindingType)) 236 { 237 try 238 { 239 binding = ConfigLoader.LookupBinding(bindingType, bindingConfigName); 240 } 241 catch (Exception e) 242 { 243 if (Fx.IsFatal(e)) 244 throw; 245 246 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MonikerSyntaxException(SR.GetString(SR.BindingLoadFromConfigFailedWith, bindingType, e.Message))); 247 } 248 if (binding == null) 249 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MonikerSyntaxException(SR.GetString(SR.BindingNotFoundInConfig, bindingType, bindingConfigName))); 250 251 } 252 253 if (binding == null) 254 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MonikerSyntaxException(SR.GetString(SR.BindingNotSpecified))); 255 256 if (string.IsNullOrEmpty(address)) 257 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MonikerSyntaxException(SR.GetString(SR.AddressNotSpecified))); 258 259 if (!string.IsNullOrEmpty(spnIdentity)) 260 { 261 if ((!string.IsNullOrEmpty(upnIdentity)) || (!string.IsNullOrEmpty(dnsIdentity))) 262 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MonikerSyntaxException(SR.GetString(SR.MonikerIncorrectServerIdentity))); 263 identity = EndpointIdentity.CreateSpnIdentity(spnIdentity); 264 } 265 else if (!string.IsNullOrEmpty(upnIdentity)) 266 { 267 if ((!string.IsNullOrEmpty(spnIdentity)) || (!string.IsNullOrEmpty(dnsIdentity))) 268 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MonikerSyntaxException(SR.GetString(SR.MonikerIncorrectServerIdentity))); 269 identity = EndpointIdentity.CreateUpnIdentity(upnIdentity); 270 } 271 else if (!string.IsNullOrEmpty(dnsIdentity)) 272 { 273 if ((!string.IsNullOrEmpty(spnIdentity)) || (!string.IsNullOrEmpty(upnIdentity))) 274 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MonikerSyntaxException(SR.GetString(SR.MonikerIncorrectServerIdentity))); 275 identity = EndpointIdentity.CreateDnsIdentity(dnsIdentity); 276 } 277 else 278 identity = null; 279 ResolveTypeIfPossible(propertyTable); 280 } 281 282 283 bool dispatchEnabled = false; CheckDispatch(ref Guid riid)284 private bool CheckDispatch(ref Guid riid) 285 { 286 if ((dispatchEnabled) && (riid == InterfaceID.idIDispatch)) 287 return true; 288 else 289 return false; 290 } 291 IProxyCreator.CreateProxy(IntPtr outer, ref Guid riid)292 ComProxy IProxyCreator.CreateProxy(IntPtr outer, ref Guid riid) 293 { 294 if (outer == IntPtr.Zero) 295 { 296 throw Fx.AssertAndThrow("OuterProxy cannot be null"); 297 } 298 299 // No contract Fault on in 300 if (contractType == null) 301 TypeCacheManager.Provider.FindOrCreateType(riid, out contractType, true, false); 302 303 if ((contractType.GUID != riid) && !(CheckDispatch(ref riid))) 304 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidCastException(SR.GetString(SR.NoInterface, riid))); 305 306 Type proxiedType = EmitterCache.TypeEmitter.FindOrCreateType(contractType); 307 ComProxy comProxy = null; 308 TearOffProxy tearoffProxy = null; 309 try 310 { 311 tearoffProxy = new TearOffProxy(this, proxiedType); 312 comProxy = ComProxy.Create(outer, tearoffProxy.GetTransparentProxy(), tearoffProxy); 313 return comProxy; 314 315 } 316 finally 317 { 318 if ((comProxy == null) && (tearoffProxy != null)) 319 ((IDisposable)tearoffProxy).Dispose(); 320 321 } 322 } 323 IProxyCreator.SupportsErrorInfo(ref Guid riid)324 bool IProxyCreator.SupportsErrorInfo(ref Guid riid) 325 { 326 if (contractType == null) 327 return false; 328 else 329 { 330 if ((contractType.GUID != riid) && !(CheckDispatch(ref riid))) 331 return false; 332 else 333 return true; 334 } 335 } 336 IProxyCreator.SupportsDispatch()337 bool IProxyCreator.SupportsDispatch() 338 { 339 return dispatchEnabled; 340 } 341 IProxyCreator.SupportsIntrinsics()342 bool IProxyCreator.SupportsIntrinsics() 343 { 344 return true; 345 } 346 } 347 } 348 349 350 351