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

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

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

      傳說中的WCF(10):消息攔截與篡改

      我們知道,在WCF中,客戶端對服務操作方法的每一次調(diào)用,都可以被看作是一條消息,而且,可能我們還會有一個疑問:如何知道客戶端與服務器通訊過 程中,期間發(fā)送和接收的SOAP是什么樣子。當然,也有人是通過借助其他工具來抓取數(shù)據(jù)包來查看。那,有沒有辦法讓程序自己輸出相應的SOAP信息呢?

      當然有,這就是我們本文要說的,對消息的攔截與篡改,呵,我用了一個不太好聽動詞——篡改。

      由于WCF的模型相對復雜,對于如何攔截和修改消息會讓許多剛接觸的朋友有點抓狂。是的,雖然MSDN文檔都有詳細的說明,但估計你也和我有相同的 感覺,看了MSDN的說明后依然一頭霧水。確實如此,畢竟WCF不像窗口和控件那樣可以看得見,理解起來比較直觀,相反的,這些東西會相對抽象。

      說到消息攔截,這個你肯定可以理解,如果你不懂,你可以想一想電話竊聽程序,我在你的手機上植入一種木馬,可以截取你和MM的通話內(nèi)容,其實這就是消息攔截。

      WCF相關的API比較難尋找,我當初也找了N久,現(xiàn)在,我直接把思路和方法告訴各位,也免得大家太辛苦。

      要對SOAP消息進行攔截和修改,我們需要實現(xiàn)兩個接口,它們都位于System.ServiceModel.Dispatcher (程序集System.ServiceModel)。下面分別價紹。

      接口一:IClientMessageInspector

      從名字中我們可以猜測,它是用來攔截客戶消息的,而看看它的方法,你就更加肯定當初的猜測了。

      • BeforeSendRequest:向服務器發(fā)送請求前攔截或修改消息(事前控制)
      • AfterReceiveReply:接收到服務器的回復消息后,在調(diào)用返回之前攔截或修改消息(事后諸葛亮)

      接口二:IDispatchMessageInspector

      剛才那個接口是針對客戶端的,而這個是針對服務器端的。

      • AfterReceiveRequest:接收客戶端請求后,在進入操作處理代碼之前攔截或修改消息(欺上)
      • BeforeSendReply:服務器向客戶端發(fā)送回復消息之前攔截和修改消息(瞞下)。

      雖然實現(xiàn)了這兩個接口,但你會有新的疑問,怎么用?把它們放到哪兒才能攔截消息?因此,下一步就是要實現(xiàn)IEndpointBehavior按口(System.ServiceModel.Description命名空間,程序集System.ServiceModel),它有四個方法,而我們只需要處理兩個就夠了。

      下面是MSDN的翻譯版本說明:

      • 使用 ApplyClientBehavior 方法可以在客戶端應用程序中修改、檢查或插入對終結點中的擴展。
      • 使用 ApplyDispatchBehavior 方法可以在服務應用程序中修改、檢查或插入對終結點范圍執(zhí)行的擴展。

        我想不用額外解釋了,說白了就是一個在客戶攔截和修改消息,另一個在服務器端攔截和修改消息。

        在實現(xiàn)這兩個方法時,和前面我們實現(xiàn)的IClientMessageInspector和IDispatchMessageInspector聯(lián)系起來就OK了。

        做完了IEndpointBehavior的事情后,把它插入到服務終結點中就行了,無論是服務器端還是客戶端,這一步都必須的,因為我們實現(xiàn)的攔 截器是包括兩個端的,因此,較好的  做法是把這些類寫到一個獨立的類庫(dll)中,這樣一來,服務器端和客戶端都可以引用它。詳見后面的示例。

        理論課上完了,下面開始實驗課,按照前面的指導思想,我們先要寫一個類庫。

        新建一個類庫應用,然后添加System.ServiceModel程序集的引用,這個不用我教你了,你懂的。

      namespace MyLib
      {
          /// <summary>
          ///  消息攔截器
          /// </summary>
          public class MyMessageInspector : IClientMessageInspector, IDispatchMessageInspector
          {
              void IClientMessageInspector.AfterReceiveReply(ref Message reply, object correlationState)
              {
                  Console.WriteLine("客戶端接收到的回復:\n{0}", reply.ToString());
              }
      
              object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel)
              {
                  Console.WriteLine("客戶端發(fā)送請求前的SOAP消息:\n{0}", request.ToString());
                  return null;
              }
      
              object IDispatchMessageInspector.AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
              {
                  Console.WriteLine("服務器端:接收到的請求:\n{0}", request.ToString());
                  return null;
              }
      
              void IDispatchMessageInspector.BeforeSendReply(ref Message reply, object correlationState)
              {
                  Console.WriteLine("服務器即將作出以下回復:\n{0}", reply.ToString());
              }
          }
      
          /// <summary>
          /// 插入到終結點的Behavior
          /// </summary>
          public class MyEndPointBehavior : IEndpointBehavior
          {
              public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
              {
                  // 不需要
                  return;
              }
      
              public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
              {
                  // 植入“偷聽器”客戶端
                  clientRuntime.MessageInspectors.Add(new MyMessageInspector());
              }
      
              public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
              {
                  // 植入“偷聽器” 服務器端
                  endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new MyMessageInspector());
              }
      
              public void Validate(ServiceEndpoint endpoint)
              {
                  // 不需要
                  return;
              }
          }
      }

      這一步,我們先建立服務器端。

      記得要引用我們剛才寫的類庫。

      namespace Server
      {
          class Program
          {
              static void Main(string[] args)
              {
                  // 服務器基址
                  Uri baseAddress = new Uri("http://localhost:1378/services");
                  // 聲明服務器主機
                  using (ServiceHost host = new ServiceHost(typeof(MyService), baseAddress))
                  {
                      // 添加綁定和終結點
                      WSHttpBinding binding = new WSHttpBinding();
                      host.AddServiceEndpoint(typeof(IService), binding, "/test");
                      // 添加服務描述
                      host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
                      // 把自定義的IEndPointBehavior插入到終結點中
                      foreach (var endpont in host.Description.Endpoints)
                      {
                          endpont.Behaviors.Add(new MyLib.MyEndPointBehavior());
                      }
                      try
                      {
                          // 打開服務
                          host.Open();
                          Console.WriteLine("服務已啟動。");
                      }
                      catch (Exception ex)
                      {
                          Console.WriteLine(ex.Message);
                      }
                      Console.ReadKey();
                  }
              }
          }
      }
      namespace Server
      {
          [ServiceContract(Namespace = "MyNamespace")]
          public interface IService
          {
              [OperationContract]
              int AddInt(int a, int b);
      
              [OperationContract]
              Student GetStudent();
      
              [OperationContract]
              CalResultResponse ComputingNumbers(CalcultRequest inMsg);
          }
      }
      namespace Server
      {
          [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
          public class MyService : IService
          {
              public int AddInt(int a, int b)
              {
                  return a + b;
              }
      
              public Student GetStudent()
              {
                  Student stu = new Student();
                  stu.StudentName = "小明";
                  stu.StudentAge = 22;
                  return stu;
              }
      
              public CalResultResponse ComputingNumbers(CalcultRequest inMsg)
              {
                  CalResultResponse rmsg = new CalResultResponse();
                  switch (inMsg.Operation)
                  {
                      case "加":
                          rmsg.ComputedResult = inMsg.NumberA + inMsg.NumberB;
                          break;
                      case "減":
                          rmsg.ComputedResult = inMsg.NumberA - inMsg.NumberB;
                          break;
                      case "乘":
                          rmsg.ComputedResult = inMsg.NumberA * inMsg.NumberB;
                          break;
                      case "除":
                          rmsg.ComputedResult = inMsg.NumberA / inMsg.NumberB;
                          break;
                      default:
                          throw new ArgumentException("運算操作只允許加、減、乘、除。");
                          break;
                  }
                  return rmsg;
              }
          }
      }
      namespace Server
      {
          [DataContract]
          public class Student
          {
              [DataMember]
              public string StudentName;
              [DataMember]
              public int StudentAge;
          }
      
          [MessageContract]
          public class CalcultRequest
          {
              [MessageHeader]
              public string Operation;
              [MessageBodyMember]
              public int NumberA;
              [MessageBodyMember]
              public int NumberB;
          }
      
          [MessageContract]
          public class CalResultResponse
          {
              [MessageBodyMember]
              public int ComputedResult;
          }
      }

      接下來,實現(xiàn)客戶端。

      a、引用剛才寫的類庫MyLib;

      b、引用WCF服務。

      namespace Client
      {
          class Program
          {
              static void Main(string[] args)
              {
                  ServiceReference1.ServiceClient client = new ServiceReference1.ServiceClient();
                  // 記得在客戶端也要插入IEndPointBehavior
                  client.Endpoint.Behaviors.Add(new MyLib.MyEndPointBehavior());
                  try
                  {
                      // 1、調(diào)用帶元數(shù)據(jù)參數(shù)和返回值的操作
                      Console.WriteLine("\n20和35相加的結果是:{0}", client.AddInt(20, 35));
                      // 2、調(diào)用帶有數(shù)據(jù)協(xié)定的操作
                      ServiceReference1.Student student = client.GetStudent();
                      Console.WriteLine("\n學生信息---------------------------");
                      Console.WriteLine("姓名:{0}\n年齡:{1}", student.StudentName, student.StudentAge);
                      // 3、調(diào)用帶消息協(xié)定的操作
                      Console.WriteLine("\n15乘以70的結果是:{0}", client.ComputingNumbers("乘", 15, 70));
                  }
                  catch (Exception ex)
                  {
                      Console.WriteLine("異常:{0}", ex.Message);
                  }
      
                  client.Close();
                  Console.ReadKey();
              }
          }
      }

      現(xiàn)在你可以運行程序來觀察了。

      知道了如何攔截消息,那么修改消息就不難了。

      現(xiàn)在我們把前面寫的類庫MyLib。

      將消息攔截器MyMessageInspector作如下修改:

          /// <summary>
          ///  消息攔截器
          /// </summary>
          public class MyMessageInspector : IClientMessageInspector, IDispatchMessageInspector
          {
              void IClientMessageInspector.AfterReceiveReply(ref Message reply, object correlationState)
              {
                  //Console.WriteLine("客戶端接收到的回復:\n{0}", reply.ToString());
                  return;
              }
      
              object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel)
              {
                  //Console.WriteLine("客戶端發(fā)送請求前的SOAP消息:\n{0}", request.ToString());
                  // 插入驗證信息
                  MessageHeader hdUserName = MessageHeader.CreateHeader("u", "fuck", "admin");
                  MessageHeader hdPassWord = MessageHeader.CreateHeader("p", "fuck", "123");
                  request.Headers.Add(hdUserName);
                  request.Headers.Add(hdPassWord);
                  return null;
              }
      
              object IDispatchMessageInspector.AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
              {
                  //Console.WriteLine("服務器端:接收到的請求:\n{0}", request.ToString());
                  // 栓查驗證信息
                  string un = request.Headers.GetHeader<string>("u", "fuck");
                  string ps = request.Headers.GetHeader<string>("p", "fuck");
                  if (un == "admin" && ps == "abcd")
                  {
                      Console.WriteLine("用戶名和密碼正確。");
                  }
                  else
                  {
                      throw new Exception("驗證失敗,滾吧!");
                  }
                  return null;
              }
      
              void IDispatchMessageInspector.BeforeSendReply(ref Message reply, object correlationState)
              {
                  //Console.WriteLine("服務器即將作出以下回復:\n{0}", reply.ToString());
                  return;
              }
          }

      注意:添加對System.Runtime.Serialization的引用。

      創(chuàng)建消息頭時,第一個參數(shù)是名字,如上面的“u”,第二個參數(shù)是命名空間,這個可以自己來定義,比如上面的“fuck”,第三個參數(shù)就是消息頭的內(nèi)容。


      現(xiàn)在重新生成一下項目,再試試。

      前面我們說過,如果安裝證書進行身份驗證會相當TMD麻煩,而可以通過修改SOAP消息頭來驗證,但是,上次的做法會有一個麻煩,那就是每次調(diào)用操作協(xié)定都要手動修改一次,這一次,我們直接在終結點級別進行修改和驗證,就省去了許多功夫。

      posted @ 2016-08-09 11:06  閆寶平  閱讀(423)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 波多野结衣av高清一区二区三区| 国产精品久久久一区二区三区 | 团风县| 一区二区三区四区五区色| 在线a级毛片无码免费真人| 日韩精品无码一区二区视频| 久久久久国产精品人妻| 真人在线射美女视频在线观看| 亚洲乱熟乱熟女一区二区| 成人3d动漫一区二区三区| WWW丫丫国产成人精品| 国产精品成人va在线播放| 国产短视频精品一区二区| 制服丝袜美腿一区二区| 国产又大又粗又爽的毛片| 久久人妻夜夜做天天爽| 国产精品成人高潮av| 忘忧草在线社区www中国中文| 亚洲精品日韩中文字幕| 免费福利视频一区二区三区高清| Y111111国产精品久久久| 国产精品九九久久精品女同| 久久88香港三级台湾三级播放| 高潮喷水抽搐无码免费| 一本色道久久东京热| 蜜桃视频网站| 亚洲国产成人无码电影| 国产亚洲欧洲av综合一区二区三区| 国产69精品久久久久人妻| 午夜一区二区三区视频| 丝袜a∨在线一区二区三区不卡| 久草国产视频| julia无码中文字幕一区| 亚洲av肉欲一区二区| 疯狂做受xxxx高潮欧美日本| 国产成人精品国内自产色| 中文字幕热久久久久久久| 日韩午夜福利视频在线观看| 高潮潮喷奶水飞溅视频无码| 视频一区视频二区制服丝袜 | 岛国av在线播放观看|