第一步:客户端New一个代理类的实例时,调用了ClientBase<TChannel>的无参构造函数,此构造函数会根据配置文件的服务配置New一个ChannelFactory<TChannel>的实例,得到一个ChannelFactory<TChannel>实例的一个引用:public ChannelFactory<TChannel> ChannelFactory { get; },看如下reflector主要代码:
System.ServiceModel.ClientBase<TChannel>的函数: protected ClientBase() { this.canShareFactory = true; this.syncRoot = new object(); this.finalizeLock = new object(); this.endpointTrait = new EndpointTrait<TChannel>("*", null, null); this.InitializeChannelFactoryRef(); } |
第二步:New一个ChannelFactory<TChannel>的实例时,调用了ChannelFactory<TChannel>的构造函数【注意:ChannelFactory<TChannel>类继ChannelFactory类,并且重写了ChannelFactory类的虚方法:protected override ServiceEndpoint CreateDescription()】,ChannelFactory<TChannel>的构造函数主要做的事情是调用基类ChannelFactory的protected void InitializeEndpoint(string configurationName, EndpointAddress address)方法,初始化服务终结点【比如地址,行为,绑定,契约等】,看如下reflector主要代码
System.ServiceModel.ChannelFactory<TChannel>函数 public ChannelFactory(string endpointConfigurationName, EndpointAddress remoteAddress) : this(typeof(TChannel)) { using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivity() : null) { if (DiagnosticUtility.ShouldUseActivity) { ServiceModelActivity.Start(activity, SR.GetString("ActivityConstructChannelFactory", new object[] { typeof(TChannel).FullName }), ActivityType.Construct); } if (endpointConfigurationName == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpointConfigurationName"); } base.InitializeEndpoint(endpointConfigurationName, remoteAddress); } } |
System.ServiceModel.ChannelFactory函数 protected void InitializeEndpoint(string configurationName, EndpointAddress address) { this.serviceEndpoint = this.CreateDescription(); ServiceEndpoint endpoint = null; if (configurationName != null) { endpoint = ConfigLoader.LookupEndpoint(configurationName, address, this.serviceEndpoint.Contract); } if (endpoint != null) { this.serviceEndpoint = endpoint; } else { if (address != null) { this.Endpoint.Address = address; } this.ApplyConfiguration(configurationName); } this.configurationName = configurationName; this.EnsureSecurityCredentialsManager(this.serviceEndpoint); } |
第三步:当客户端的通过代理类的实例调用服务方法时,实际上服务方法被代理类又重新封装了一次,代理实现这个服务方法很简单:调用了ClientBase<TChannel>类的channel属性,类似:base.Channel.服务方法,通过对此属性的调用将创建信道【通过调用上面创建的public ChannelFactory<TChannel>ChannelFactory 的 CreateChannel()方法】
System.ServiceModel.ClientBase<TChannel>方法 protected TChannel Channel { get { if (this.channel == null) { lock (this.ThisLock) { if (this.channel == null) { using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivity() : null) { if (DiagnosticUtility.ShouldUseActivity) { ServiceModelActivity.Start(activity, SR.GetString("ActivityOpenClientBase", new object[] { typeof(TChannel).FullName }), ActivityType.OpenClient); } if (this.useCachedFactory) { try { this.CreateChannelInternal(); } catch (Exception exception) { if (!this.useCachedFactory || ((!(exception is CommunicationException) && !(exception is ObjectDisposedException)) && !(exception is TimeoutException))) { throw; } DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Warning); this.InvalidateCacheAndCreateChannel(); } } else { this.CreateChannelInternal(); } } } } } return this.channel; } } |
由于第三步创建信道的时候会做很多工作,现将第三步分解来看:
1)调用System.ServiceModel.ChannelFactory的OnOpening()方法创建ServiceChannelFactory类型的具体实例【根据终结点所需的信道形状】,比如 如果是Request/Reply方式,具体实例就是ServiceChannelFactoryOverRequest类型的实例,该类继承抽象类ServiceChannelFactory,通过执行基类ServiceChannelFactory的构造函数初始化clientRuntime,bindingName等属性,通过执行基类TypedServiceChannelFactory<TChannel> 的构造函数,初始化IChannelFactory<TChannel>类型的innerChannelFactory属性,如果是basichttpbinding,那么IChannelFactory<TChannel>类型是HttpChannelFactory
System.ServiceModel.Channels.ChannelFactory方法 protected virtual IChannelFactory CreateFactory() { if (this.Endpoint == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("SFxChannelFactoryCannotCreateFactoryWithoutDescription"))); } if (this.Endpoint.Binding != null) { return ServiceChannelFactory.BuildChannelFactory(this.Endpoint, this.UseActiveAutoClose); } if (this.configurationName != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("SFxChannelFactoryNoBindingFoundInConfig1", new object[] { this.configurationName }))); } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("SFxChannelFactoryNoBindingFoundInConfigOrCode"))); } |
2)调用ServiceChannelFactoryOverRequest类型实例的CreateChannel方法
System.ServiceModel.Channels.ServiceChannelFactory方法 public object CreateChannel(Type channelType, EndpointAddress address, Uri via) { if (via == null) { via = this.ClientRuntime.Via; if (via == null) { via = address.Uri; } } ServiceChannel serviceChannel = this.CreateServiceChannel(address, via); serviceChannel.Proxy = CreateProxy(channelType, channelType, MessageDirection.Input, serviceChannel); serviceChannel.ClientRuntime.GetRuntime().InitializeChannel((IClientChannel) serviceChannel.Proxy); OperationContext current = OperationContext.Current; if ((current != null) && (current.InstanceContext != null)) { current.InstanceContext.WmiChannels.Add((IChannel) serviceChannel.Proxy); serviceChannel.WmiInstanceContext = current.InstanceContext; } return serviceChannel.Proxy; } |
3) 调用CreateInnerChannelBinder方法【被ServiceChannelFactoryOverRequest 重写】创建 RequestChannelBinder类型的实例【注意:属性channel的值是HttpChannelFactory.CreateChannel()的HttpRequestChannel】;然后创建ServiceChannel类型的实例【将ServiceChannelFactoryOverRequest实例和RequestChannelBinder实例作为参数传入ServiceChannel的构造函数生成其实例】
System.ServiceModel.Channels.ServiceChannelFactory的方法 public virtual ServiceChannel CreateServiceChannel(EndpointAddress address, Uri via) { IChannelBinder binder = this.CreateInnerChannelBinder(address, via); ServiceChannel channel = new ServiceChannel(this, binder); if (binder is DuplexChannelBinder) { DuplexChannelBinder binder2 = binder as DuplexChannelBinder; binder2.ChannelHandler = new ChannelHandler(this.messageVersion, binder, channel); binder2.DefaultCloseTimeout = this.DefaultCloseTimeout; binder2.DefaultSendTimeout = this.DefaultSendTimeout; binder2.IdentityVerifier = this.clientRuntime.IdentityVerifier; } return channel; }protected override IChannelBinder CreateInnerChannelBinder(EndpointAddress to, Uri via) { return new RequestChannelBinder(base.InnerChannelFactory.CreateChannel(to, via)); } |
System.ServiceModel.Channels.ServiceChannelFactory [SecuritySafeCritical] internal static object CreateProxy(Type interfaceType, Type proxiedType, MessageDirection direction, ServiceChannel serviceChannel) { if (!proxiedType.IsInterface) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("SFxChannelFactoryTypeMustBeInterface"))); } ServiceChannelProxy proxy = new ServiceChannelProxy(interfaceType, proxiedType, direction, serviceChannel); return proxy.GetTransparentProxy(); } |
5)调用方法时调用ServiceChannelProxy 的Invoke
private IMethodReturnMessage InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) { object[] objArray; object[] ins = operation.MapSyncInputs(methodCall, out objArray); object ret = this.serviceChannel.Call(operation.Action, operation.IsOneWay, operation, ins, objArray); object[] returnArgs = operation.MapSyncOutputs(methodCall, objArray, ref ret); return this.CreateReturnMessage(ret, returnArgs, methodCall); } |
System.ServiceModel.Channels.ServiceChannel方法 internal object Call(string action, bool oneway, ProxyOperationRuntime operation, object[] ins, object[] outs) { return this.Call(action, oneway, operation, ins, outs, this.operationTimeout); } |
6)调用RequestChannelBinder.Request()
public Message Request(Message message, TimeSpan timeout) { return this.channel.Request(message, timeout); } |
7)调用HttpChannelRequest.SendRequest
总结如下:(引自Scott.X.Liu)
在客户端自动生成的实例中
是从ClientBase<of T>.Channel属性开始的,最终要创建T的透明代理,然后调用。
以BasicHttpBinding为例,客户端请求的主要步骤如下:
1 根据传入的Binding和EndpointAddress生成ServiceEndpoint
2 再根据ServiceEndpoint的类型生成ServiceChannelFactory 类的实例
当前BasicHttpBinding 生成的应该是ServiceChannelFactoryOverRequest类的实例,
对应的IChannelBinder是RequestChannelBinder
注:
basicHttpBinding.BuildChannelFactory<IRequestChannel>要对 basicHttpBinding所有的绑定元素进行遍历
默认情况下,不启用https,则传输元素使用HttpTransportBindingElement,该对象重写BuildChannelFactory<IRequestChannel>,返回值是HttpChannelFactory
RequestChannelBinder对象最重要的字段是channel,对应的值是HttpChannelFactory.CreateChannel(),返回的值是HttpChannelFactory.HttpRequestChannel
3 生成ServiceChannel,将ServiceChannelFactoryOverRequest和RequestChannelBinder做为参数传入ServiceChannel
构造函数为ServiceChannel(ServiceChannelFactory factory, IChannelBinder binder)
4. 生成T的透理代理ServiceChannelProxy,将ServiceChannel做为参数传入ServiceChannelProxy,构造
5.在调用透明代理相应的方法时,调用ServiceChannelProxy.Invoke(),
如果是Service,调用ServiceChannel.Call(),此时实质是调用ServiceChannel封装的IChannelBinder(当前是RequestChannelBinder)的call,
6 调用RequestChannelBinder.Request(),注意步骤2最后一句,此时channel是HttpChannelFactory.HttpRequestChannel
HttpChannelFactory.HttpRequestChannel创建 HttpChannelRequest的请求,然后调用HttpChannelRequest.SendRequest发送消息
其实质就是封装一个HttpWebRequest,将Message发送到服务器端address里,根,webservice的最终原理是一样的
因此,要抓住几个关系点,从总体上把握客户端请求的流程
(1 ServiceChannelFactory 类的实例是什么类型
(2 IChannelBinder接口的实现是什么类型
(3 IChannelBinder.Channel是什么