<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      深入理解WCF系統體系(之二:WCF客戶端如何構建?(上))

        前一節(《WCF體系架構(之一:Client與Server信息交互處理流程初略介紹)》)大致介紹了WCF服務消息處理的大致流程,WCF服務的消費者可以是WEB客戶端、也可以是其他語言開發的應用程序。
        對于WEB客戶端以及其他語言的應用程序,跨平臺的性能主要是通過HTTP協議+SOAP消息機制實現。本節主要詳細介紹消息在WCF客戶端應用程序消息處理流程
      ------------------------------------------------------------------
      -目錄:
      -1、WCF通過客戶端代理調用 服務
      -2、實際代理如何映射到服務目標對象上
      -3、WCF客戶端框架的核心ClientRuntime建立過程
      -4、ImmutableClientRuntime對象的作用
      -5、客戶端操作選擇器MethodInfoOperationSelector
      -6、ProxyOperationRuntime的作用
      ------------------------------------------------------------------


      1、WCF如何處理客戶端消息調                          


        如果有.Net Remoting開發經驗,大家一定還記得在Remoting的客戶端,調用服務通過透明代理(TransparentProxy)來對服務進行調用,然后透明代理將對服務的調用轉交給實際代理(RealProxy)。在WCF同樣如此。那透明代理對應的實際代理又是什么類型的呢。?看看下面的測試例子就知道了。

      var instanceContext = new InstanceContext(new CalculatorCallback());
      using (var channkeFactory = new DuplexChannelFactory<ICalculator>(instanceContext, "calculator"))
      { 
          ICalculator proxy = channkeFactory.CreateChannel(); 
          Console.WriteLine("是否是透明代   理:"+RemotingServices.IsTransparentProxy(proxy));
          Console.WriteLine("透明代理類型:" + proxy.GetType());
      }
      

       輸出結果如下:

       

      2、實際代理如何映射到服務目標對象上              


      首先看看實際代理對象ServiceChannelProxy字段的定義:

      internal sealed class ServiceChannelProxy : RealProxy, IRemotingTypeInfo
      {
        // Fields
        private const string activityIdSlotName = "E2ETrace.ActivityID";
        private Type interfaceType;
        private MethodDataCache methodDataCache;
        private MbrObject objectWrapper;
        private Type proxiedType;
        private ImmutableClientRuntime proxyRuntime;
        private ServiceChannel serviceChannel;
        /*
        */
        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;
      }
      
        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);
        }
      }
      

        先對這幾個對象做個介紹:

      1. interfaceType與proxiedType就是服務契約的Type,methodDataCache存放方法信息的容器
      2. objectWrapper:建立代理對象與服務對象之間映射關系的對象
      3. proxyRuntime:是恒定客戶端運行時(這個是我自己翻譯的,只在此有意義。為了區分它與客戶端運行時ClientRuntime的區別而已)。同ClientRuntime一樣,它也是WCF客戶端體系中很重要的一個對象,它涉及到調用信息的序列化、反序列化、IClientOperationsSelector、IClientMessageInspector、IChannelInitializer等核心對象,稍后會介紹到。
      4. serviceChannel:服務信道。

      其中有個 MbrObject類型的 objectWrapper定義。MbrObject的定義如下:

      private class MbrObject : MarshalByRefObject
      {
        // Fields
        private RealProxy proxy;
        private Type targetType;
      
        // Methods
        internal MbrObject(RealProxy proxy, Type targetType)
        {
          this.proxy = proxy;
          this.targetType = targetType;
        }
      
        public override bool Equals(object obj)
        {
          return object.ReferenceEquals(obj, this.proxy.GetTransparentProxy());
        }
      
        public override int GetHashCode()
        {
          return this.proxy.GetHashCode();
        }
      
        public override string ToString()
        {
          return this.targetType.ToString();
        }
      }
      

        看看它的構造函數使用的參數可知:通過實際代理對象以及目標代理類型,將實際代理對象映射到了實現契約接口的對象上。

        還有個問題:RealProxy是映射到了最終服務對象上,那是通過什么樣的方式或者說是如何進行映射的呢。?
      ServiceChannelProxy對象在WCF體系內部構造ServiceChannelProxy對象時有個構造函數,它建立了代理對象與實際服務對象:this.objectWrapper = new MbrObject(this, proxiedType);這樣就建立了代理對象同服務對象之間的映射。

        查看代理信息就發現了他們之間的關系,如下圖:

       


      客戶端調用服務端方法最終通過ServiceChannelProxy進行調用。以上只列出了同步調用的方法,在ServiceChannelFactory中還有異步調用的方法,詳情請參見ServiceChannelFactory類。
      從InvokeService中可以看出,進行調用的時候,使用了serviceChannel.Call進行調用。同樣,在異步方法中也是通過ServiceChannel對象的BeginInvoke與EndInvoke進行調用。也就是說最終的調用是通過ServiceChannel完成。

       

      3、WCF客戶端框架的核心ClientRuntime建立過程


        ClientRuntime是與WCF服務端框架中DispatchRuntime對應的客戶端框架的核心。那么ClientRuntime是如何建立的。?

        ClientRuntime建立的過程比較復雜。下面通過序號標明ClientRuntime建立的過程。

      3.1、建立Channel                                                       


        無論在WCF的客戶端還是服務端,我們通常都會選擇一種或者多種通信協議。綁定協議包含許多綁定元素(BindingElementCollection)。以NetTcpBinding來說,它就包含 以下四種綁定元素:
      TransactionFlowBindingElement context;
      BinaryMessageEncodingBindingElement encoding;
      ReliableSessionBindingElement session;
      TcpTransportBindingElement transport;

      每個綁定元素穿件信道工廠,BindingElementCollection創建的是信道工廠堆棧,信道就是由這些ChannelFactory Stack按照順序依次建立起來的Channel Stack。


      3.2、建立過程ChannelFactory                                       


        先看看以下例子:var channkeFactory = new DuplexChannelFactory<ICalculator>(instanceContext, "calculator");這樣就信道工廠就建立。在這個例子中用回調對象對象與EndpointName為參數建立ChannelFactory。

      DuplexChannelFactory有很多構造器,
      public class DuplexChannelFactory<TChannel> : ChannelFactory<TChannel>
      {
        // Methods
        public DuplexChannelFactory(object callbackObject) : base(typeof(TChannel))
        {
          using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivity() : null)
          {
            if (DiagnosticUtility.ShouldUseActivity)
            {
              ServiceModelActivity.Start(activity, SR.GetString("ActivityConstructChannelFactory", new object[] { TraceUtility.CreateSourceString(this) }), ActivityType.Construct);
            }
            if (callbackObject == null)
            {
              throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("callbackObject");
            }
            this.CheckAndAssignCallbackInstance(callbackObject);
            base.InitializeEndpoint((string) null, null);
          }
        }
      
      public DuplexChannelFactory(object callbackObject, string endpointConfigurationName) : this(callbackObject, endpointConfigurationName, (EndpointAddress) null)
      {
      }
      
      public DuplexChannelFactory(object callbackObject, string endpointConfigurationName, EndpointAddress remoteAddress) : base(typeof(TChannel))
      {
        using (ServiceModelActivity activity = DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.CreateBoundedActivity() : null)
        {
          if (DiagnosticUtility.ShouldUseActivity)
          {
            ServiceModelActivity.Start(activity, SR.GetString("ActivityConstructChannelFactory", new object[] { TraceUtility.CreateSourceString(this) }), ActivityType.Construct);
          }
          if (callbackObject == null)
          {
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("callbackObject");
          }
          if (endpointConfigurationName == null)
          {
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("endpointConfigurationName");
          }
          this.CheckAndAssignCallbackInstance(callbackObject);
          base.InitializeEndpoint(endpointConfigurationName, remoteAddress);
        }
       }
      /*
      ......
      */
      }
      

        

      以上列舉了上述例子中使用的構造器。從中可知:在創建ChannelFactory的過程中,通過ChannelFactory<TChannel>的InitializeEndpoint對Endpoint進行了初始化。


      3.3、根據建立的Endpoint創建ServiceChannelFactory              

       

      internal abstract class ServiceChannelFactory : ChannelFactoryBase
      {
        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));
        }
      }
      

       

      從ClientRuntime clientRuntime = DispatcherBuilder.BuildProxyBehavior(serviceEndpoint, out parameters);

      可知:ClientRuntime 由DispatcherBuilder創建。
      注:ServiceChannel由ServiceChannelFactory創建,同ServiceChannelProxy使用。在創建ServiceChannel的過程中對Channel進行初始化。處理函數如下:

      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, serviceChanne);
          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.4、DispatcherBuilder創建ClientRuntime

      internal class DispatcherBuilder
      {
        internal static ClientRuntime BuildProxyBehavior(ServiceEndpoint serviceEndpoint, out BindingParameterCollection parameters)
        {
          parameters = new BindingParameterCollection();
          SecurityContractInformationEndpointBehavior.ClientInstance.AddBindingParameters(serviceEndpoint, parameters);
          AddBindingParameters(serviceEndpoint, parameters);
          ContractDescription contract = serviceEndpoint.Contract;
          ClientRuntime parent = new ClientRuntime(contract.Name, contract.Namespace);
          parent.ContractClientType = contract.ContractType;
          IdentityVerifier property = serviceEndpoint.Binding.GetProperty<IdentityVerifier>(parameters);
          if (property != null)
          {
            parent.IdentityVerifier = property;
          }
          for (int i = 0; i < contract.Operations.Count; i++)
          {
            OperationDescription operation = contract.Operations[i];
            if (!operation.IsServerInitiated())
            {
              BuildProxyOperation(operation, parent);
            }
            else
            {
              BuildDispatchOperation(operation, parent.CallbackDispatchRuntime, null);
            }
          }
          ApplyClientBehavior(serviceEndpoint, parent);
          return parent;
        }
      /**/
      }
      

        由Endpoint信息可以獲取到ContractDescription,進而獲取到Operations等等,從而賦值給ClientRuntime對象,完成ClientRuntime對象的建立。

      以上還有個問題:DispatchRuntime 是與ClientRuntime相對象的WCF服務端分發運行時,同ClientRuntime一樣,它是WCF服務端核心對象。在客戶端怎么會后服務端的的分發運行時呢。?原因很簡單,在WCF數據包模式以及Request-Reply模式下,DispatchRuntime是不需要的,但是在雙工模式時,Server端與Client端已經不明確,
      Server與Client互發消息,即是服務端也是客戶端。所以不僅在ClientRuntime中存在DispatchRuntime,在DispatchRuntime同樣存在ClientRuntime。

      ClientRuntime作為客戶端框架的核心,它決定著消息的格式化(IClientMessageFormatter)、客戶端操作選擇器(IClientOperationSelector)、客戶端消息檢查器(IClientMessageInspectors)等等。

      4、ImmutableClientRuntime對象的作用                   


        客戶端對服務端的操作是通過TransparentProxy到RealProxy,也就是ServiceChannelProxy對象中。上面提到過,客戶端調用服務的實際代理ServiceChannelProxy對象有一個名稱為proxyRuntime的字段,類型就是ImmutableClientRuntime。
        ImmutableClientRuntime對象依賴于ClientRuntime,這點可以從ImmutableClientRuntime的構造函數中就可以看出。

      internal ImmutableClientRuntime(ClientRuntime behavior)
      {
          this.channelInitializers = EmptyArray<IChannelInitializer>.ToArray(behavior.ChannelInitializers);
          this.interactiveChannelInitializers = EmptyArray<IInteractiveChannelInitializer>.ToArray(behavior.InteractiveChannelInitializers);
          this.messageInspectors = EmptyArray<IClientMessageInspector>.ToArray(behavior.MessageInspectors);
          this.operationSelector = behavior.OperationSelector;
          this.useSynchronizationContext = behavior.UseSynchronizationContext;
          this.validateMustUnderstand = behavior.ValidateMustUnderstand;
          this.unhandled = new ProxyOperationRuntime(behavior.UnhandledClientOperation, this);
          this.addTransactionFlowProperties = behavior.AddTransactionFlowProperties;
          this.operations = new Dictionary<string, ProxyOperationRuntime>();
          for (int i = 0; i < behavior.Operations.Count; i++)
          {
            ClientOperation operation = behavior.Operations[i];
            ProxyOperationRuntime runtime = new ProxyOperationRuntime(operation, this);
            this.operations.Add(operation.Name, runtime);
          }
          this.correlationCount = this.messageInspectors.Length + behavior.MaxParameterInspectors;
      }
      

       

      ImmutableClientRuntime在RealProxy中起著至關重要的作用。如下圖是RealProxy的信息:

      由上圖可知:

      1、operations為Dictionary<string, ProxyOperationRuntime>類型,其中key為契約接口中標識位OperationContractAttribute的方法名,Value為ProxyOperationRuntime。

      2、MessageInspector是實現了IClientMessageInspector接口的Microsoft.VisualStudio.Diagnostics.ServiceModelSink.StubClientEventSink類型。
      3、客戶端OperationSelector是MethodInfoOperationSelector類型的,MethodInfoOperationSelector實現了IClientOperationSelector接口。
      4、客戶端消息檢查器IClientMessageInspectors為Microsoft.VisualStudio.Diagnostics.ServiceModelSink.StubClientEventSink類型。


      5、客戶端操作選擇器MethodInfoOperationSelector。             


      通過工具看看MethodInfoOperationSelector的定義如下:

      internal class MethodInfoOperationSelector : IClientOperationSelector
      {
        // Fields
        private Dictionary<object, string> operationMap = new Dictionary<object, string>();
      
        // Methods
        internal MethodInfoOperationSelector(ContractDescription description, MessageDirection directionThatRequiresClientOpSelection)
        {
          for (int i = 0; i < description.Operations.Count; i++)
          {
            OperationDescription description2 = description.Operations[i];
            if (description2.Messages[0].Direction == directionThatRequiresClientOpSelection)
            {
              if ((description2.SyncMethod != null) && !this.operationMap.ContainsKey(description2.SyncMethod.MethodHandle))
              {
                this.operationMap.Add(description2.SyncMethod.MethodHandle, description2.Name);
              }
              if ((description2.BeginMethod != null) && !this.operationMap.ContainsKey(description2.BeginMethod.MethodHandle))
              {
              this.operationMap.Add(description2.BeginMethod.MethodHandle, description2.Name);
              this.operationMap.Add(description2.EndMethod.MethodHandle, description2.Name);
              }
            }
          }
        }
      
        public string SelectOperation(MethodBase method, object[] parameters)
        {
          if (this.operationMap.ContainsKey(method.MethodHandle))
          {
            return this.operationMap[method.MethodHandle];
          }
          return null;
        }
      
        // Properties
        public bool AreParametersRequiredForSelection
        {
          get
          {
            return false;
          }
        }
      }
      

        

      operationMap為存放方法的字段,key方法句柄信息,Value為方法名。
      MethodInfoOperationSelector通過SelectOperation根據方法句柄值獲取方法名,然后通過方法名,獲取ProxyOperationRuntime對象。


      查看OperationSelector的operationMap中Add方法的句柄值如下圖所示:


      通過控制臺輸出契約接口中方法的句柄值如下:


      -6、ProxyOperationRuntime的作用                                     

      了解它的作用,還是從源碼開始。

      internal class ProxyOperationRuntime
      {
          // Fields
          private string action;
          private MethodInfo beginMethod;
          private bool deserializeReply;
          internal static readonly object[] EmptyArray = new object[0];
          private ParameterInfo[] endOutParams;
          private readonly IClientFaultFormatter faultFormatter;
          private readonly IClientMessageFormatter formatter;
          private ParameterInfo[] inParams;
          private readonly bool isInitiating;
          private readonly bool isOneWay;
          private readonly bool isTerminating;
          private readonly string name;
          internal static readonly ParameterInfo[] NoParams = new ParameterInfo[0];
          private ParameterInfo[] outParams;
          private readonly IParameterInspector[] parameterInspectors;
          private readonly ImmutableClientRuntime parent;
          private string replyAction;
          private ParameterInfo returnParam;
          private bool serializeRequest;
          private MethodInfo syncMethod;
      
          // Methods
          internal ProxyOperationRuntime(ClientOperation operation, ImmutableClientRuntime parent)
          {
            if (operation == null)
            {
              throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operation");
            }
            if (parent == null)
            {
              throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parent");
            }
            this.parent = parent;
            this.formatter = operation.Formatter;
            this.isInitiating = operation.IsInitiating;
            this.isOneWay = operation.IsOneWay;
            this.isTerminating = operation.IsTerminating;
            this.name = operation.Name;
            this.parameterInspectors = EmptyArray<IParameterInspector>.ToArray(operation.ParameterInspectors);
            this.faultFormatter = operation.FaultFormatter;
            this.serializeRequest = operation.SerializeRequest;
            this.deserializeReply = operation.DeserializeReply;
            this.action = operation.Action;
            this.replyAction = operation.ReplyAction;
            this.beginMethod = operation.BeginMethod;
            this.syncMethod = operation.SyncMethod;
            if (this.beginMethod != null)
            {
              this.inParams = ServiceReflector.GetInputParameters(this.beginMethod, true);
              if (this.syncMethod != null)
              {
                this.outParams = ServiceReflector.GetOutputParameters(this.syncMethod, false);
              }
              else
              {
                this.outParams = NoParams;
              }
              this.endOutParams = ServiceReflector.GetOutputParameters(operation.EndMethod, true);
              this.returnParam = operation.EndMethod.ReturnParameter;
            }
            else if (this.syncMethod != null)
            {
              this.inParams = ServiceReflector.GetInputParameters(this.syncMethod, false);
              this.outParams = ServiceReflector.GetOutputParameters(this.syncMethod, false);
              this.returnParam = this.syncMethod.ReturnParameter;
            }
            if ((this.formatter == null) && (this.serializeRequest || this.deserializeReply))
            {
              throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("ClientRuntimeRequiresFormatter0", new object[] { this.name })));
            }
          }
      }
        internal void AfterReply(ref ProxyRpc rpc)
        {
          if (!this.isOneWay)
          {
            Message reply = rpc.Reply;
            if (this.deserializeReply)
            {
              rpc.ReturnValue = this.formatter.DeserializeReply(reply, rpc.OutputParameters);
            }
            else
            {
              rpc.ReturnValue = reply;
            }
            int parameterInspectorCorrelationOffset = this.parent.ParameterInspectorCorrelationOffset;
            try
            {
              for (int i = this.parameterInspectors.Length - 1; i >= 0; i--)
              {
                this.parameterInspectors[i].AfterCall(this.name, rpc.OutputParameters, rpc.ReturnValue, rpc.Correlation[parameterInspectorCorrelationOffset + i]);
                if (TD.ClientParameterInspectorAfterCallInvokedIsEnabled())
                {
                  TD.ClientParameterInspectorAfterCallInvoked(this.parameterInspectors[i].GetType().FullName);
                }
              }
            }
            catch (Exception exception)
            {
              if (Fx.IsFatal(exception))
              {
                throw;
              }
              if (ErrorBehavior.ShouldRethrowClientSideExceptionAsIs(exception))
              {
                throw;
              }
              throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception);
            }
            if (this.parent.ValidateMustUnderstand)
            {
              Collection<MessageHeaderInfo> headersNotUnderstood = reply.Headers.GetHeadersNotUnderstood();
              if ((headersNotUnderstood != null) && (headersNotUnderstood.Count > 0))
              {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.GetString("SFxHeaderNotUnderstood", new object[] { headersNotUnderstood[0].Name, headersNotUnderstood[0].Namespace })));
              }
            }
          }
        }
      
        internal void BeforeRequest(ref ProxyRpc rpc)
        {
          int parameterInspectorCorrelationOffset = this.parent.ParameterInspectorCorrelationOffset;
          try
          {
            for (int i = 0; i < this.parameterInspectors.Length; i++)
            {
              rpc.Correlation[parameterInspectorCorrelationOffset + i] = this.parameterInspectors[i].BeforeCall(this.name, rpc.InputParameters);
              if (TD.ClientParameterInspectorBeforeCallInvokedIsEnabled())
              {
                TD.ClientParameterInspectorBeforeCallInvoked(this.parameterInspectors[i].GetType().FullName);
              }
            }
          }
          catch (Exception exception)
          {
            if (Fx.IsFatal(exception))
            {
              throw;
            }
            if (ErrorBehavior.ShouldRethrowClientSideExceptionAsIs(exception))
            {
              throw;
            }
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(exception);
          }
          if (this.serializeRequest)
          {
            rpc.Request = this.formatter.SerializeRequest(rpc.MessageVersion, rpc.InputParameters);
          }
          else
          {
            if (rpc.InputParameters[0] == null)
            {
              throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("SFxProxyRuntimeMessageCannotBeNull", new object[] { this.name })));
            }
            rpc.Request = (Message) rpc.InputParameters[0];
            if (!IsValidAction(rpc.Request, this.Action))
            {
              object[] args = new object[] { this.Name, rpc.Request.Headers.Action ?? "{NULL}", this.Action };
              throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("SFxInvalidRequestAction", args)));
            }
          }
        }

      由上圖可以得知:
      1、對返回值進行序列化時,使用的類型是PrimitiveOperationFormatter,它同時實現了客戶端序列化接口IClientMessageFormatter與服務端序列化IDispatchMessageFormatter接口
      2、錯誤契約使用的序列化器是DataContractSerializerFaultFormatter。
      3、對服務調用參數的序列化以及參數檢查,對返回消息進行反序列化及參數檢查通過ProxyOperationRuntime對象完成。

        對實際代理ServiceChannelProxy對象中的ImmutableClientRuntime類型的字段realProxy以及realProxy的MessageInspector、operations添加監視,查看其信息如下:

      圖1:realProxy監視信息

      圖2:realProxy的消息檢查器MessageInspector監視信息

      圖3:realProxy的operations監視信息

      由以上3個圖中顯示的信息可知:

      1、operations為Dictionary<string, ProxyOperationRuntime>類型,其中key為契約接口中標識位OperationContractAttribute的方法名,Value為ProxyOperationRuntime。

      2、MessageInspector是實現了IClientMessageInspector接口的客戶端消息檢查器Microsoft.VisualStudio.Diagnostics.ServiceModelSink.StubClientEventSink類型。
      3、客戶端OperationSelector是MethodInfoOperationSelector類型的,MethodInfoOperationSelector實現了IClientOperationSelector接口。

      參考:http://www.rzrgm.cn/artech/tag/WCF/

         《WCF揭秘》

      posted @ 2012-03-31 14:30  tyb1222  閱讀(3342)  評論(3)    收藏  舉報
      主站蜘蛛池模板: 国产精品亚洲欧美大片在线看 | 午夜成人鲁丝片午夜精品| 国产精品国产三级国快看| 国产日韩综合av在线| 一本一道av中文字幕无码| 国产超级va在线观看视频| 九九热在线精品视频99| 国产一区二区日韩经典| 亚洲中文字幕无码久久2017| 国产精品一码在线播放| 少妇人妻真实偷人精品| 成人麻豆日韩在无码视频| 亚洲国产欧美在线人成aaaa| 亚洲精品天堂一区二区| 巩留县| 亚洲一区二区av在线| 男人扒女人添高潮视频| 一本无码人妻在中文字幕免费 | 天水市| 亚洲另类欧美在线电影| 久久精品人妻无码专区 | 91亚洲国产三上悠亚在线播放| 999国产精品999久久久久久 | 国产成人精品亚洲午夜| 久热综合在线亚洲精品| 国产中年熟女高潮大集合| 亚洲精品乱码久久久久久中文字幕| 国内少妇人妻偷人精品| 性一交一乱一乱一视频| 加勒比精品一区二区三区| 狠狠综合久久综合88亚洲| 亚洲精品三区二区一区一| 男人狂桶女人出白浆免费视频| 女人被狂躁c到高潮喷水一区二区 女高中生自慰污污网站 | 中文字幕国产精品第一页| 亚洲精品久久久久久下一站| 视频一区视频二区制服丝袜 | 精品国产一区二区三区香| 在线日韩日本国产亚洲| 国产精品播放一区二区三区 | 久久精品无码免费不卡|