WCF学习笔记3(客户端内部运行机制分析)

第一步:客户端New一个代理类的实例时,调用了ClientBase<TChannel>的无参构造函数,此构造函数会根据配置文件的服务配置New一个ChannelFactory<TChannel>的实例,得到一个ChannelFactory<TChannel>实例的一个引用:public ChannelFactory<TChannel> ChannelFactory { get; },看如下reflector主要代码:

 ClientBase()
{
    .canShareFactory = ;
    .syncRoot =  object();
    .finalizeLock =  object();
    .endpointTrait =  EndpointTrait<TChannel>(, , );
    .InitializeChannelFactoryRef();
}

 第二步:New一个ChannelFactory<TChannel>的实例时,调用了ChannelFactory<TChannel>的构造函数【注意:ChannelFactory<TChannel>类继ChannelFactory类,并且重写了ChannelFactory类的虚方法:protected override ServiceEndpoint CreateDescription()】,ChannelFactory<TChannel>的构造函数主要做的事情是调用基类ChannelFactoryprotected void InitializeEndpoint(string configurationName, EndpointAddress address)方法,初始化服务终结点【比如地址,行为,绑定,契约等】,看如下reflector主要代码

 ChannelFactory(string endpointConfigurationName, EndpointAddress remoteAddress) : this((TChannel))
{
     (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivity() : )
    {
         (DiagnosticUtility.ShouldUseActivity)
        {
            ServiceModelActivity.Start(activity, SR.GetString(,  object[] { (TChannel).FullName }), ActivityType.Construct);
        }
         (endpointConfigurationName == )
        {
             DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull();
        }
        .InitializeEndpoint(endpointConfigurationName, remoteAddress);
    }
}

 void InitializeEndpoint(string configurationName, EndpointAddress address)
{
    .serviceEndpoint = .CreateDescription();
    ServiceEndpoint endpoint = ;
     (configurationName != )
    {
        endpoint = ConfigLoader.LookupEndpoint(configurationName, address, .serviceEndpoint.Contract);
    }
     (endpoint != )
    {
        .serviceEndpoint = endpoint;
    }
    
    {
         (address != )
        {
            .Endpoint.Address = address;
        }
        .ApplyConfiguration(configurationName);
    }
    .configurationName = configurationName;
    .EnsureSecurityCredentialsManager(.serviceEndpoint);
}

第三步:当客户端的通过代理类的实例调用服务方法时,实际上服务方法被代理类又重新封装了一次,代理实现这个服务方法很简单:调用了ClientBase<TChannel>类的channel属性,类似:base.Channel.服务方法,通过对此属性的调用将创建信道【通过调用上面创建的public ChannelFactory<TChannel>ChannelFactory 的 CreateChannel()方法】

 TChannel Channel
{
    
    {
         (.channel == )
        {
             (.ThisLock)
            {
                 (.channel == )
                {
                     (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivity() : )
                    {
                         (DiagnosticUtility.ShouldUseActivity)
                        {
                            ServiceModelActivity.Start(activity, SR.GetString(,  object[] { (TChannel).FullName }), ActivityType.OpenClient);
                        }
                         (.useCachedFactory)
                        {
                            
                            {
                                .CreateChannelInternal();
                            }
                             (Exception exception)
                            {
                                 (!.useCachedFactory || ((!(exception  CommunicationException) && !(exception  ObjectDisposedException)) && !(exception  TimeoutException)))
                                {
                                    ;
                                }
                                DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Warning);
                                .InvalidateCacheAndCreateChannel();
                            }
                        }
                        
                        {
                            .CreateChannelInternal();
                        }
                    }
                }
            }
        }
         .channel;
    }
}

 

由于第三步创建信道的时候会做很多工作,现将第三步分解来看:

1)调用System.ServiceModel.ChannelFactory的OnOpening()方法创建ServiceChannelFactory类型的具体实例【根据终结点所需的信道形状】,比如 如果是Request/Reply方式,具体实例就是ServiceChannelFactoryOverRequest类型的实例,该类继承抽象类ServiceChannelFactory,通过执行基类ServiceChannelFactory的构造函数初始化clientRuntimebindingName等属性,通过执行基类TypedServiceChannelFactory<TChannel> 的构造函数,初始化IChannelFactory<TChannel>类型的innerChannelFactory属性,如果是basichttpbinding,那么IChannelFactory<TChannel>类型是HttpChannelFactory

  IChannelFactory CreateFactory()
{
     (.Endpoint == )
    {
         DiagnosticUtility.ExceptionUtility.ThrowHelperError( InvalidOperationException(SR.GetString()));
    }
     (.Endpoint.Binding != )
    {
         ServiceChannelFactory.BuildChannelFactory(.Endpoint, .UseActiveAutoClose);
    }
     (.configurationName != )
    {
         DiagnosticUtility.ExceptionUtility.ThrowHelperError( InvalidOperationException(SR.GetString(,  object[] { .configurationName })));
    }
     DiagnosticUtility.ExceptionUtility.ThrowHelperError( InvalidOperationException(SR.GetString()));
}
 
  ServiceChannelFactory BuildChannelFactory(ServiceEndpoint serviceEndpoint, bool useActiveAutoClose)
{
    ChannelRequirements requirements;
    BindingParameterCollection parameters;
     (serviceEndpoint == )
    {
         DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull();
    }
    serviceEndpoint.EnsureInvariants();
    serviceEndpoint.ValidateForClient();
    ChannelRequirements.ComputeContractRequirements(serviceEndpoint.Contract,  requirements);
    ClientRuntime clientRuntime = DispatcherBuilder.BuildProxyBehavior(serviceEndpoint,  parameters);
    Binding binding = serviceEndpoint.Binding;
    Type[] requiredChannels = ChannelRequirements.ComputeRequiredChannels( requirements);
    CustomBinding binding2 =  CustomBinding(binding);
    BindingContext context =  BindingContext(binding2, parameters);
    InternalDuplexBindingElement internalDuplexBindingElement = ;
    InternalDuplexBindingElement.AddDuplexFactorySupport(context,  internalDuplexBindingElement);
    binding2 =  CustomBinding(context.RemainingBindingElements);
    binding2.CopyTimeouts(serviceEndpoint.Binding);
     (Type type  requiredChannels)
    {
         ((type == (IOutputChannel)) && binding2.CanBuildChannelFactory<IOutputChannel>(parameters))
        {
              ServiceChannelFactoryOverOutput(binding2.BuildChannelFactory<IOutputChannel>(parameters), clientRuntime, binding);
        }
         ((type == (IRequestChannel)) && binding2.CanBuildChannelFactory<IRequestChannel>(parameters))
        {
              ServiceChannelFactoryOverRequest(binding2.BuildChannelFactory<IRequestChannel>(parameters), clientRuntime, binding);
        }
         ((type == (IDuplexChannel)) && binding2.CanBuildChannelFactory<IDuplexChannel>(parameters))
        {
             (requirements.usesReply && binding.CreateBindingElements().Find<TransportBindingElement>().ManualAddressing)
            {
                 DiagnosticUtility.ExceptionUtility.ThrowHelperError( InvalidOperationException(SR.GetString()));
            }
              ServiceChannelFactoryOverDuplex(binding2.BuildChannelFactory<IDuplexChannel>(parameters), clientRuntime, binding);
        }
         ((type == (IOutputSessionChannel)) && binding2.CanBuildChannelFactory<IOutputSessionChannel>(parameters))
        {
              ServiceChannelFactoryOverOutputSession(binding2.BuildChannelFactory<IOutputSessionChannel>(parameters), clientRuntime, binding, );
        }
         ((type == (IRequestSessionChannel)) && binding2.CanBuildChannelFactory<IRequestSessionChannel>(parameters))
        {
              ServiceChannelFactoryOverRequestSession(binding2.BuildChannelFactory<IRequestSessionChannel>(parameters), clientRuntime, binding, );
        }
         ((type == (IDuplexSessionChannel)) && binding2.CanBuildChannelFactory<IDuplexSessionChannel>(parameters))
        {
             (requirements.usesReply && binding.CreateBindingElements().Find<TransportBindingElement>().ManualAddressing)
            {
                 DiagnosticUtility.ExceptionUtility.ThrowHelperError( InvalidOperationException(SR.GetString()));
            }
              ServiceChannelFactoryOverDuplexSession(binding2.BuildChannelFactory<IDuplexSessionChannel>(parameters), clientRuntime, binding, useActiveAutoClose);
        }
    }
     (Type type2  requiredChannels)
    {
         ((type2 == (IOutputChannel)) && binding2.CanBuildChannelFactory<IOutputSessionChannel>(parameters))
        {
              ServiceChannelFactoryOverOutputSession(binding2.BuildChannelFactory<IOutputSessionChannel>(parameters), clientRuntime, binding, );
        }
         ((type2 == (IRequestChannel)) && binding2.CanBuildChannelFactory<IRequestSessionChannel>(parameters))
        {
              ServiceChannelFactoryOverRequestSession(binding2.BuildChannelFactory<IRequestSessionChannel>(parameters), clientRuntime, binding, );
        }
         (((type2 == (IRequestSessionChannel)) && binding2.CanBuildChannelFactory<IRequestChannel>(parameters)) && (binding2.GetProperty<IContextSessionProvider>(parameters) != ))
        {
              ServiceChannelFactoryOverRequest(binding2.BuildChannelFactory<IRequestChannel>(parameters), clientRuntime, binding);
        }
    }
    Dictionary<Type, byte> dictionary =  Dictionary<Type, byte>();
     (binding2.CanBuildChannelFactory<IOutputChannel>(parameters))
    {
        dictionary.Add((IOutputChannel), );
    }
     (binding2.CanBuildChannelFactory<IRequestChannel>(parameters))
    {
        dictionary.Add((IRequestChannel), );
    }
     (binding2.CanBuildChannelFactory<IDuplexChannel>(parameters))
    {
        dictionary.Add((IDuplexChannel), );
    }
     (binding2.CanBuildChannelFactory<IOutputSessionChannel>(parameters))
    {
        dictionary.Add((IOutputSessionChannel), );
    }
     (binding2.CanBuildChannelFactory<IRequestSessionChannel>(parameters))
    {
        dictionary.Add((IRequestSessionChannel), );
    }
     (binding2.CanBuildChannelFactory<IDuplexSessionChannel>(parameters))
    {
        dictionary.Add((IDuplexSessionChannel), );
    }
     DiagnosticUtility.ExceptionUtility.ThrowHelperError(ChannelRequirements.CantCreateChannelException(dictionary.Keys, requiredChannels, binding.Name));
}

2)调用ServiceChannelFactoryOverRequest类型实例的CreateChannel方法

 object CreateChannel(Type channelType, EndpointAddress address, Uri via)
{
     (via == )
    {
        via = .ClientRuntime.Via;
         (via == )
        {
            via = address.Uri;
        }
    }
    ServiceChannel serviceChannel = .CreateServiceChannel(address, via);
    serviceChannel.Proxy = CreateProxy(channelType, channelType, MessageDirection.Input, serviceChannel);
    serviceChannel.ClientRuntime.GetRuntime().InitializeChannel((IClientChannel) serviceChannel.Proxy);
    OperationContext current = OperationContext.Current;
     ((current != ) && (current.InstanceContext != ))
    {
        current.InstanceContext.WmiChannels.Add((IChannel) serviceChannel.Proxy);
        serviceChannel.WmiInstanceContext = current.InstanceContext;
    }
     serviceChannel.Proxy;
}

3) 调用CreateInnerChannelBinder方法【被ServiceChannelFactoryOverRequest 重写】创建 RequestChannelBinder类型的实例【注意:属性channel的值是HttpChannelFactory.CreateChannel()的HttpRequestChannel】;然后创建ServiceChannel类型的实例【将ServiceChannelFactoryOverRequest实例和RequestChannelBinder实例作为参数传入ServiceChannel的构造函数生成其实例】

  ServiceChannel CreateServiceChannel(EndpointAddress address, Uri via)
{
    IChannelBinder binder = .CreateInnerChannelBinder(address, via);
    ServiceChannel channel =  ServiceChannel(, binder);
     (binder  DuplexChannelBinder)
    {
        DuplexChannelBinder binder2 = binder  DuplexChannelBinder;
        binder2.ChannelHandler =  ChannelHandler(.messageVersion, binder, channel);
        binder2.DefaultCloseTimeout = .DefaultCloseTimeout;
        binder2.DefaultSendTimeout = .DefaultSendTimeout;
        binder2.IdentityVerifier = .clientRuntime.IdentityVerifier;
    }
     channel;
}
  IChannelBinder CreateInnerChannelBinder(EndpointAddress to, Uri via)
{
      RequestChannelBinder(.InnerChannelFactory.CreateChannel(to, via));
}

4)生成ServiceChannelProxy

System.ServiceModel.Channels.ServiceChannelFactory
[SecuritySafeCritical]
  object CreateProxy(Type interfaceType, Type proxiedType, MessageDirection direction, ServiceChannel serviceChannel)
{
     (!proxiedType.IsInterface)
    {
         DiagnosticUtility.ExceptionUtility.ThrowHelperError( InvalidOperationException(SR.GetString()));
    }
    ServiceChannelProxy proxy =  ServiceChannelProxy(interfaceType, proxiedType, direction, serviceChannel);
     proxy.GetTransparentProxy();
}

5)调用方法时调用ServiceChannelProxyInvoke

  IMessage Invoke(IMessage message)
{
    IMessage message3;
    
    {
        IMethodCallMessage methodCall = message  IMethodCallMessage;
         (methodCall == )
        {
             DiagnosticUtility.ExceptionUtility.ThrowHelperError( ArgumentException(SR.GetString()));
        }
        MethodData methodData = .GetMethodData(methodCall);
         (methodData.MethodType)
        {
             MethodType.Service:
                 .InvokeService(methodCall, methodData.Operation);

             MethodType.BeginService:
                 .InvokeBeginService(methodCall, methodData.Operation);

             MethodType.EndService:
                 .InvokeEndService(methodCall, methodData.Operation);

             MethodType.Channel:
                 .InvokeChannel(methodCall);

             MethodType.Object:
                 .InvokeObject(methodCall);

             MethodType.GetType:
                 .InvokeGetType(methodCall);
        }
         DiagnosticUtility.ExceptionUtility.ThrowHelperError( InvalidOperationException(string.Format(CultureInfo.InvariantCulture, ,  object[])));
    }
     (Exception exception)
    {
         (Fx.IsFatal(exception))
        {
            ;
        }
        message3 = .CreateReturnMessage(exception, message  IMethodCallMessage);
    }
     message3;
}
 IMethodReturnMessage InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
{
    object[] objArray;
    object[] ins = operation.MapSyncInputs(methodCall,  objArray);
    object ret = .serviceChannel.Call(operation.Action, operation.IsOneWay, operation, ins, objArray);
    object[] returnArgs = operation.MapSyncOutputs(methodCall, objArray,  ret);
     .CreateReturnMessage(ret, returnArgs, methodCall);
}
 object Call(string action, bool oneway, ProxyOperationRuntime operation, object[] ins, object[] outs)
{
     .Call(action, oneway, operation, ins, outs, .operationTimeout);
}

6)调用RequestChannelBinder.Request()

 
     
 Message Request(Message message, TimeSpan timeout)
{
     .channel.Request(message, timeout);
}

7)调用HttpChannelRequest.SendRequest

 

 void SendRequest(Message message, TimeSpan timeout)
{
    TimeoutHelper timeoutHelper =  TimeoutHelper(timeout);
    .factory.ApplyManualAddressing( .to,  .via, message);
    .webRequest = .channel.GetWebRequest(.to, .via,  timeoutHelper);
    Message message2 = message;
    
    {
         (.channel.State != CommunicationState.Opened)
        {
            .Cleanup();
            .channel.ThrowIfDisposedOrNotOpen();
        }
        HttpChannelUtilities.SetRequestTimeout(.webRequest, timeoutHelper.RemainingTime());
        HttpOutput output = HttpOutput.CreateHttpOutput(.webRequest, .factory, message2, .factory.IsChannelBindingSupportEnabled);
        bool flag = ;
        
        {
            output.Send(timeoutHelper.RemainingTime());
            .channelBinding = output.TakeChannelBinding();
            output.Close();
            flag = ;
             (TD.MessageSentByTransportIsEnabled())
            {
                TD.MessageSentByTransport(.to.Uri.AbsoluteUri);
            }
        }
        
        {
             (!flag)
            {
                output.Abort(HttpAbortReason.Aborted);
            }
        }
    }
    
    {
         (!object.ReferenceEquals(message2, message))
        {
            message2.Close();
        }
    }
}

 

总结如下:(引自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是什么

 

转载于:https://www.cnblogs.com/syf/archive/2012/04/29/2476317.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值