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