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

第一步:客户端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>的构造函数主要做的事情是调用基类ChannelFactoryprotected 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的构造函数初始化clientRuntimebindingName等属性,通过执行基类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")));
}

 
System.ServiceModel.Channels.ServiceChannelFactory方法
public static ServiceChannelFactory BuildChannelFactory(ServiceEndpoint serviceEndpoint, bool useActiveAutoClose)
{
    ChannelRequirements requirements;
    BindingParameterCollection parameters;
    if (serviceEndpoint == null)
    {
        throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serviceEndpoint");
    }
    serviceEndpoint.EnsureInvariants();
    serviceEndpoint.ValidateForClient();
    ChannelRequirements.ComputeContractRequirements(serviceEndpoint.Contract, out requirements);
    ClientRuntime clientRuntime = DispatcherBuilder.BuildProxyBehavior(serviceEndpoint, out parameters);
    Binding binding = serviceEndpoint.Binding;
    Type[] requiredChannels = ChannelRequirements.ComputeRequiredChannels(ref requirements);
    CustomBinding binding2 = new CustomBinding(binding);
    BindingContext context = new BindingContext(binding2, parameters);
    InternalDuplexBindingElement internalDuplexBindingElement = null;
    InternalDuplexBindingElement.AddDuplexFactorySupport(context, ref internalDuplexBindingElement);
    binding2 = new CustomBinding(context.RemainingBindingElements);
    binding2.CopyTimeouts(serviceEndpoint.Binding);
    foreach (Type type in requiredChannels)
    {
        if ((type == typeof(IOutputChannel)) && binding2.CanBuildChannelFactory<IOutputChannel>(parameters))
        {
            return new ServiceChannelFactoryOverOutput(binding2.BuildChannelFactory<IOutputChannel>(parameters), clientRuntime, binding);
        }
        if ((type == typeof(IRequestChannel)) && binding2.CanBuildChannelFactory<IRequestChannel>(parameters))
        {
            return new ServiceChannelFactoryOverRequest(binding2.BuildChannelFactory<IRequestChannel>(parameters), clientRuntime, binding);
        }
        if ((type == typeof(IDuplexChannel)) && binding2.CanBuildChannelFactory<IDuplexChannel>(parameters))
        {
            if (requirements.usesReply && binding.CreateBindingElements().Find<TransportBindingElement>().ManualAddressing)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("CantCreateChannelWithManualAddressing")));
            }
            return new ServiceChannelFactoryOverDuplex(binding2.BuildChannelFactory<IDuplexChannel>(parameters), clientRuntime, binding);
        }
        if ((type == typeof(IOutputSessionChannel)) && binding2.CanBuildChannelFactory<IOutputSessionChannel>(parameters))
        {
            return new ServiceChannelFactoryOverOutputSession(binding2.BuildChannelFactory<IOutputSessionChannel>(parameters), clientRuntime, binding, false);
        }
        if ((type == typeof(IRequestSessionChannel)) && binding2.CanBuildChannelFactory<IRequestSessionChannel>(parameters))
        {
            return new ServiceChannelFactoryOverRequestSession(binding2.BuildChannelFactory<IRequestSessionChannel>(parameters), clientRuntime, binding, false);
        }
        if ((type == typeof(IDuplexSessionChannel)) && binding2.CanBuildChannelFactory<IDuplexSessionChannel>(parameters))
        {
            if (requirements.usesReply && binding.CreateBindingElements().Find<TransportBindingElement>().ManualAddressing)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("CantCreateChannelWithManualAddressing")));
            }
            return new ServiceChannelFactoryOverDuplexSession(binding2.BuildChannelFactory<IDuplexSessionChannel>(parameters), clientRuntime, binding, useActiveAutoClose);
        }
    }
    foreach (Type type2 in requiredChannels)
    {
        if ((type2 == typeof(IOutputChannel)) && binding2.CanBuildChannelFactory<IOutputSessionChannel>(parameters))
        {
            return new ServiceChannelFactoryOverOutputSession(binding2.BuildChannelFactory<IOutputSessionChannel>(parameters), clientRuntime, binding, true);
        }
        if ((type2 == typeof(IRequestChannel)) && binding2.CanBuildChannelFactory<IRequestSessionChannel>(parameters))
        {
            return new ServiceChannelFactoryOverRequestSession(binding2.BuildChannelFactory<IRequestSessionChannel>(parameters), clientRuntime, binding, true);
        }
        if (((type2 == typeof(IRequestSessionChannel)) && binding2.CanBuildChannelFactory<IRequestChannel>(parameters)) && (binding2.GetProperty<IContextSessionProvider>(parameters) != null))
        {
            return new ServiceChannelFactoryOverRequest(binding2.BuildChannelFactory<IRequestChannel>(parameters), clientRuntime, binding);
        }
    }
    Dictionary<Type, byte> dictionary = new Dictionary<Type, byte>();
    if (binding2.CanBuildChannelFactory<IOutputChannel>(parameters))
    {
        dictionary.Add(typeof(IOutputChannel), 0);
    }
    if (binding2.CanBuildChannelFactory<IRequestChannel>(parameters))
    {
        dictionary.Add(typeof(IRequestChannel), 0);
    }
    if (binding2.CanBuildChannelFactory<IDuplexChannel>(parameters))
    {
        dictionary.Add(typeof(IDuplexChannel), 0);
    }
    if (binding2.CanBuildChannelFactory<IOutputSessionChannel>(parameters))
    {
        dictionary.Add(typeof(IOutputSessionChannel), 0);
    }
    if (binding2.CanBuildChannelFactory<IRequestSessionChannel>(parameters))
    {
        dictionary.Add(typeof(IRequestSessionChannel), 0);
    }
    if (binding2.CanBuildChannelFactory<IDuplexSessionChannel>(parameters))
    {
        dictionary.Add(typeof(IDuplexSessionChannel), 0);
    }
    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ChannelRequirements.CantCreateChannelException(dictionary.Keys, requiredChannels, binding.Name));
}

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));
}

4)生成ServiceChannelProxy

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)调用方法时调用ServiceChannelProxyInvoke

System.ServiceModel.Channels.ServiceChannelProxy方法
public override IMessage Invoke(IMessage message)
{
    IMessage message3;
    try
    {
        IMethodCallMessage methodCall = message as IMethodCallMessage;
        if (methodCall == null)
        {
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString("SFxExpectedIMethodCallMessage")));
        }
        MethodData methodData = this.GetMethodData(methodCall);
        switch (methodData.MethodType)
        {
            case MethodType.Service:
                return this.InvokeService(methodCall, methodData.Operation);

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

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

            case MethodType.Channel:
                return this.InvokeChannel(methodCall);

            case MethodType.Object:
                return this.InvokeObject(methodCall);

            case MethodType.GetType:
                return this.InvokeGetType(methodCall);
        }
        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Invalid proxy method type", new object[0])));
    }
    catch (Exception exception)
    {
        if (Fx.IsFatal(exception))
        {
            throw;
        }
        message3 = this.CreateReturnMessage(exception, message as IMethodCallMessage);
    }
    return message3;
}

System.ServiceModel.Channels.ServiceChannelProxy方法
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()

System.ServiceModel.Channels.RequestChannelBinder方法
public Message Request(Message message, TimeSpan timeout)
{
    return this.channel.Request(message, timeout);
}

7)调用HttpChannelRequest.SendRequest

System.ServiceModel.Channels.HttpChannelFactory+HttpRequestChannel+HttpChannelRequest
public void SendRequest(Message message, TimeSpan timeout)
{
    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
    this.factory.ApplyManualAddressing(ref this.to, ref this.via, message);
    this.webRequest = this.channel.GetWebRequest(this.to, this.via, ref timeoutHelper);
    Message message2 = message;
    try
    {
        if (this.channel.State != CommunicationState.Opened)
        {
            this.Cleanup();
            this.channel.ThrowIfDisposedOrNotOpen();
        }
        HttpChannelUtilities.SetRequestTimeout(this.webRequest, timeoutHelper.RemainingTime());
        HttpOutput output = HttpOutput.CreateHttpOutput(this.webRequest, this.factory, message2, this.factory.IsChannelBindingSupportEnabled);
        bool flag = false;
        try
        {
            output.Send(timeoutHelper.RemainingTime());
            this.channelBinding = output.TakeChannelBinding();
            output.Close();
            flag = true;
            if (TD.MessageSentByTransportIsEnabled())
            {
                TD.MessageSentByTransport(this.to.Uri.AbsoluteUri);
            }
        }
        finally
        {
            if (!flag)
            {
                output.Abort(HttpAbortReason.Aborted);
            }
        }
    }
    finally
    {
        if (!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/p/2476317.html