乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      .NET Remoting監(jiān)聽端口的Windows Service

       ThinkTank_引擎 2014-11-20
         

      所謂.NET Remoting就是跨應(yīng)用程序域邊界調(diào)用程序集。如圖23-16所示,顯示了.NET Remoting應(yīng)用程序的基本構(gòu)架。

      文本框:  
圖23-16  .NET Remoting
應(yīng)用程序基本構(gòu)架

從圖23-16中看到,Remoting服務(wù)端承載遠(yuǎn)程對象,使外界能與之通信,對外的信道可以是HTTP、TCP或者IPC。HTTP方式的信道在跨越防火墻上有優(yōu)勢;TCP方式的信道常用在局域網(wǎng)內(nèi)通信,速度比HTTP快很多;IPC信道用于同一臺機(jī)器的進(jìn)程間通信,通信不占用網(wǎng)絡(luò)資源,速度又比TCP快很多。因此,這里的服務(wù)器是一個(gè)廣義的概念,對于TCP和HTTP信道,服務(wù)器可以是兩個(gè)獨(dú)立的物理計(jì)算機(jī)。

      那么,最基本的.NET Remoting應(yīng)用程序應(yīng)該由三部分構(gòu)成:

      ·      服務(wù)端。承載遠(yuǎn)程對象。

      ·      遠(yuǎn)程對象。需要跨應(yīng)用程序域邊界調(diào)用的程序集。

      ·      客戶端。用于調(diào)用遠(yuǎn)程對象。

      遠(yuǎn)程對象是根本,服務(wù)端只是一個(gè)載體,那么我們就先來創(chuàng)建一個(gè)簡單的遠(yuǎn)程對象:

      1.繼續(xù)使用前面的一個(gè)解決方案。右鍵單擊解決方案,選擇“添加”→“新建項(xiàng)目”命令,新建一個(gè)TestRemoteObject類庫項(xiàng)目。

      2.把默認(rèn)的Class1.cs重命名為RemoteObject.cs,打開cs文件,修改代碼為:

      using System;

      namespace RemoteObject

      {

          public class MyObject : MarshalByRefObject

          {

              public int Add(int a, int b)

              {

                  return a + b;

              }

          }

      }

      在RemoteObject命名空間下有一個(gè)MyObject類,除了繼承MarshalByRefObject類使之能跨應(yīng)用程序域邊界被訪問之外,和一般的類沒有任何區(qū)別。

      3.右鍵單擊這個(gè)類庫項(xiàng)目,如圖23-17所示。

      圖23-17  項(xiàng)目屬性

      我們看到這個(gè)項(xiàng)目的程序集名為TestRemoteObject,默認(rèn)的命名空間為TestRemoteObject。默認(rèn)的命名空間名字和程序集的名字是一樣的,但是在代碼中我們的命名空間名字為RemoteObject,和程序集名字不同以便進(jìn)行區(qū)分。

      注意:程序集和命名空間是兩個(gè)不同的概念,一個(gè)程序集可以包括幾個(gè)命名空間,一個(gè)命名空間也可以由多個(gè)程序集來實(shí)現(xiàn)。

      在創(chuàng)建了遠(yuǎn)程對象后就需要?jiǎng)?chuàng)建Remoting服務(wù)端來發(fā)布這個(gè)遠(yuǎn)程對象了。

      4.服務(wù)端可以是一個(gè)控制臺應(yīng)用程序、Windows應(yīng)用程序、Windows服務(wù)甚至是IIS。為了簡單,我們將首先使用控制臺應(yīng)用程序做服務(wù)端。在解決方案中新建一個(gè)名為TestRemotingConsoleServer的控制臺應(yīng)用程序,然后右鍵單擊項(xiàng)目,選擇添加應(yīng)用,如圖23-18所示,添加System.Runtime.Remoting的引用。

      5.把Program.cs修改成如下:

      using System;

      using System.Runtime.Remoting;

      using System.Runtime.Remoting.Channels;

      using System.Runtime.Remoting.Channels.Tcp;

      namespace TestRemotingConsoleServer

      {

          class Program

          {

              static void Main(string[] args)

              {

                  // 新建一個(gè)TCP信道

                  TcpChannel tc = new TcpChannel(9999);

                  // 注冊TCP信道

                  ChannelServices.RegisterChannel(tc, false);

                  // 注冊知名對象

                  RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteObject.

                  MyObject), "myObject", WellKnownObjectMode.SingleCall);

                  // 讓控制臺不會自動關(guān)閉

                  Console.ReadLine();

              }

          }

      }

      圖23-18  添加System.Runtime.Remoting的引用

      我們看到,使用.NET Remoting發(fā)布遠(yuǎn)程對象并不復(fù)雜,首先需要告知程序使用哪種信道發(fā)布遠(yuǎn)程對象。在這里我們選擇TCP信道,并在9999端口通信。然后要告知程序把對象注冊為哪種類型,在這里筆者不想詳細(xì)闡述遠(yuǎn)程對象的種類和模式,讀者只需要理解在這里我們把Remote- Object.MyObject這個(gè)類型使用一個(gè)固定的名字myObject來發(fā)布(因此叫做知名對象),對象的模式是SingleCall,SingleCall模式的對象是無狀態(tài)的。

      最后我們來完成用客戶端應(yīng)用程序調(diào)用遠(yuǎn)程對象??蛻舳藨?yīng)用程序可以是ASP.NET應(yīng)用程序、控制臺應(yīng)用程序或者Windows應(yīng)用程序。那么,我們就直接使用前一節(jié)建立的ASP.NET應(yīng)用程序作為客戶端吧。

      6.在TestWeb網(wǎng)站下新建一個(gè)RemotingTest.aspx,然后在頁面的Page_Load事件處理方法中調(diào)用遠(yuǎn)程對象。

      protected void Page_Load(object sender, EventArgs e)

      {

          RemoteObject.MyObject mo = (RemoteObject.MyObject)Activator.GetObject

          (typeof(RemoteObject.MyObject), "tcp://localhost:9999/myObject");

          Response.Write(mo.Add(1, 2));

      }

      在這里,我們從遠(yuǎn)程地址tcp://localhost:9999/myObject創(chuàng)建遠(yuǎn)程對象,并調(diào)用了對象的Add()方法。myObject就是在服務(wù)端中為知名對象起的名字。

      7.編譯整個(gè)解決方案,IDE提示“找不到命名空間RemoteObject”,這是因?yàn)槲覀兊目蛻舳撕头?wù)端項(xiàng)目沒有引用遠(yuǎn)程對象類庫項(xiàng)目。右鍵單擊服務(wù)端項(xiàng)目,選擇“添加引用”,在項(xiàng)目頁中找到類庫項(xiàng)目,單擊“確定”按鈕,如圖23-19所示。

      對于客戶端項(xiàng)目也同樣添加類庫的引用,然后重新編譯解決方案。

      8.現(xiàn)在就能進(jìn)行測試了。解決方案中的項(xiàng)目如圖23-20所示。

                         

                                    圖23-19  添加項(xiàng)目引用                                                                  圖23-20  解決方案中的項(xiàng)目

      要讓遠(yuǎn)程調(diào)用成功運(yùn)行,先要啟動服務(wù)端使之監(jiān)聽端口。如圖23-20所示,單擊控制臺應(yīng)用程序,項(xiàng)目名自動以粗體標(biāo)識,表示這是當(dāng)前項(xiàng)目,按Ctrl+F5組合鍵直接啟動程序。然后再單擊TestWeb網(wǎng)站,右鍵單擊RemotingTest.aspx,選擇設(shè)為起始頁,按Ctrl+F5組合鍵啟動網(wǎng)站。

      如圖23-21所示,頁面顯示3,成功了!

      圖23-21  調(diào)用遠(yuǎn)程對象

      注意圖23-21所示,在整個(gè)過程中需要確保服務(wù)端處于運(yùn)行狀態(tài)。至此,我們完成了第一個(gè).NET Remoting應(yīng)用程序。

      23.3.2  Remoting的信道

      前面提到過,Remoting有多種信道可以選擇,這大大增加了我們分布式系統(tǒng)的靈活性。如果希望在廣域網(wǎng)通信,可以使用HTTP信道,如果希望在局域網(wǎng)通信取得更好的性能,可以使用TCP信道,如果希望在本機(jī)上的不同進(jìn)程間通信以獲得最好的性能,可以使用IPC信道。

      下面我們來修改前面的程序,使之使用三種不同的Remoting信道,并且我們要比較三種信道在效率上差多少:

      1.首先在遠(yuǎn)程對象中新增一個(gè)方法,使之返回大量的數(shù)據(jù)。

      using System;

      namespace RemoteObject

      {

          public class MyObject : MarshalByRefObject

          {

              public int Add(int a, int b)

              {

                  return a + b;

              }

              public string[] GetData()

              {

                  string[] data = new string[100000];

                  for (int i = 0; i < data.Length; i++)

                      data[i] = "很大量的數(shù)據(jù)"+i;

                  return data;

              }

          }

      }

      2.然后修改服務(wù)端,使之在三個(gè)不同的信道上發(fā)布遠(yuǎn)程對象。

      using System;

      using System.Runtime.Remoting;

      using System.Runtime.Remoting.Channels;

      using System.Runtime.Remoting.Channels.Tcp;

      using System.Runtime.Remoting.Channels.Http;

      using System.Runtime.Remoting.Channels.Ipc;

      namespace TestRemotingConsoleServer

      {

          class Program

          {

              static void Main(string[] args)

              {

                  // 新建一個(gè)TCP信道

                  TcpChannel tc = new TcpChannel(9999);

                  // 新建一個(gè)HTTP信道

                  HttpChannel hc = new HttpChannel(8888);

                  // 新建一個(gè)IPC信道

                  IpcChannel ic = new IpcChannel("testPipe");

                  // 注冊TCP信道

                  ChannelServices.RegisterChannel(tc, false);

                  ChannelServices.RegisterChannel(hc, false);

                  ChannelServices.RegisterChannel(ic, false);

                  // 注冊知名對象

                  RemotingConfiguration.RegisterWellKnownServiceType(typeof

                  (RemoteObject.MyObject), "myObject", WellKnownObjectMode.SingleCall);

                  // 讓控制臺不會自動關(guān)閉

                  Console.ReadLine();

              }

          }

      }

      注意,由于是在同一個(gè)機(jī)器上注冊多個(gè)信道,需要給每個(gè)信道使用不同的端口。對于IPC信道來說,使用一個(gè)管道名來區(qū)分而不是端口號。為了能更好地測試三者的差別,我們把服務(wù)端部署到另外一個(gè)服務(wù)器上(把EXE文件和DLL文件復(fù)制過去)。

      3.在RemotingTest.aspx頁面上新建三個(gè)按鈕用于使用不同的信道調(diào)用遠(yuǎn)程對象。

      <asp:Button ID="btn_HttpChannel" runat="server" Text="http通道"/>

      <asp:Button ID="btn_TcpChannel" runat="server" Text="tcp通道"/>

      <asp:Button ID="btn_IpcChannel" runat="server" Text="ipc通道"/>

      按鈕的單擊事件處理方法如下:

      protected void btn_HttpChannel_Click(object sender, EventArgs e)

      {

          System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();

          sw.Start();

          RemoteObject.MyObject mo = (RemoteObject.

          MyObject)Activator.GetObject(typeof(RemoteObject.MyObject),

          "http://srv-devapphost:8888/myObject");

          Response.Write("HTTP信道<br/>");

          Response.Write(string.Format("記錄數(shù):{0}條<br/>", mo.GetData().Length));

          Response.Write(string.Format("花費(fèi)時(shí)間:{0}毫秒<br/>", sw.ElapsedMilliseconds));

      }

      protected void btn_TcpChannel_Click(object sender, EventArgs e)

      {

          System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();

          sw.Start();

          RemoteObject.MyObject mo = (RemoteObject.MyObject)Activator.GetObject

          (typeof(RemoteObject.MyObject), "tcp://srv-devapphost:9999/myObject");

          Response.Write("TCP信道<br/>");

          Response.Write(string.Format("記錄數(shù):{0}條<br/>", mo.GetData().Length));

          Response.Write(string.Format("花費(fèi)時(shí)間:{0}毫秒<br/>", sw.ElapsedMilliseconds));

      }

      protected void btn_IpcChannel_Click(object sender, EventArgs e)

      {

          System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();

          sw.Start();

          RemoteObject.MyObject mo = (RemoteObject.

          MyObject)Activator.GetObject(typeof(RemoteObject.MyObject),

          "ipc://testPipe/myObject");

          Response.Write("IPC信道<br/>");

          Response.Write(string.Format("記錄數(shù):{0}條<br/>", mo.GetData().Length));

          Response.Write(string.Format("花費(fèi)時(shí)間:{0}毫秒<br/>", sw.ElapsedMilliseconds));

      }

      可以看到,使用三種信道調(diào)用的代碼僅在URL上有區(qū)別。在這里我們不但把服務(wù)端部署到了遠(yuǎn)程服務(wù)器上,而且在本地也開了一個(gè)服務(wù)端用于在IPC上注冊遠(yuǎn)程對象。

      4.測試結(jié)果如圖23-22所示。

      圖23-22  Remoting的三種信道

      可以看到在效率上三者有明顯的差別。IPC比TCP快是因?yàn)樗鼈鬟f數(shù)據(jù)不經(jīng)過網(wǎng)絡(luò),不占用網(wǎng)絡(luò)資源。TCP比HTTP快很多是因?yàn)槟J(rèn)情況下TCP信道使用二進(jìn)制序列化,序列化后的數(shù)據(jù)量很小,而HTTP默認(rèn)使用SOAP消息進(jìn)行格式化,基于XML的SOAP消息非常臃腫,因此在傳輸上會比TCP花費(fèi)更多的時(shí)間。不過不可否認(rèn)HTTP信道在跨防火墻上的優(yōu)勢,因此使用哪種信道還需要根據(jù)自己的需求來選擇。

      23.3.3  使用配置文件增加靈活性

      雖然我們做的Remoting程序可以正常使用,但是整個(gè)程序非常不靈活:

      ·      服務(wù)端有關(guān)信道、端口等的配置都直接寫死在程序里面。

      ·      客戶端設(shè)置的遠(yuǎn)程對象的地址也是寫死在程序里面的。

      對于客戶端的配置不是大問題,因?yàn)槠鋵?shí)那個(gè)URL就是一個(gè)字符串。而服務(wù)端的配置文件應(yīng)該怎么做呢?其實(shí)一點(diǎn)也不復(fù)雜,添加一個(gè)app.config然后寫入下面的內(nèi)容:

      <?xml version="1.0" encoding="utf-8" ?>

      <configuration>

        <system.runtime.remoting>

          <application name="RemoteHostService">

            <service>

              <wellknown type="RemoteObject.MyObject, TestRemoteObject" objectUri=

              "myObject" mode="SingleCall" />

            </service>

            <channels>

              <channel ref="tcp" port="9999" />

              <channel ref="http" port="8888" />

              <channel ref="ipc" portName="testPipe" />

            </channels>

          </application>

        </system.runtime.remoting>

      </configuration>

      可以看到配置文件主要由兩部分構(gòu)成:

      ·      定義遠(yuǎn)程對象類型的service節(jié)點(diǎn)。在這里我們定義了一個(gè)知名對象,模式是SingleCall,對象名為myObject。

      ·      定義信道的channels節(jié)點(diǎn)。在這里定義了三個(gè)信道,和先前程序方式定義的一樣。

      特別需要注意的是,這里的type="RemoteObject.MyObject,TestRemoteObject",格式是:

      type="命名空間.類型名,程序集名"

      對比圖23-17看看,現(xiàn)在你知道為什么當(dāng)時(shí)筆者要把命名空間、類型和程序集三者的名字設(shè)置不同了吧。那么,怎么讓服務(wù)端加載配置文件讀取Remoting的配置呢?只需要一行代碼就行。

      RemotingConfiguration.Configure("TestRemotingConsoleServer.exe.config", false);

      Console.ReadLine();

      你可能會奇怪,配置文件是app.config,為什么這里寫成了應(yīng)用程序名.config呢?其實(shí)在編譯的時(shí)候IDE會自動把配置文件進(jìn)行改名,以免發(fā)生沖突,如圖23-23所示,可以看到Release目錄的        文件。

      圖23-23  服務(wù)端程序release文件夾

      真正有用的是加亮的三個(gè)文件(分別是遠(yuǎn)程對象、服務(wù)端和配置文件),在部署的時(shí)候只需要復(fù)制這些文件即可。

      雖然改了服務(wù)端,但是我們并沒有改變通道的端口,因此客戶端不需要做任何修改就能直接運(yùn)行。如果你希望把URL從程序中分離的話,可以在配置文件中添加幾個(gè)節(jié)點(diǎn)。

      <appSettings>

          <add key="HTTPChannel" value="http://localhost:8888/myObject"/>

          <add key="TCPChannel" value="tcp://localhost:9999/myObject"/>

          <add key="IPCChannel" value="ipc://testPipe/myObject"/>

      </appSettings>

      然后在代碼中調(diào)用配置文件讀取URL。

      RemoteObject.MyObject mo = (RemoteObject.MyObject)

      Activator.GetObject(typeof(RemoteObject.MyObject),

      ConfigurationManager.AppSettings["HTTPChannel"]);

      其他兩個(gè)信道的代碼差不多,就不列出來了?,F(xiàn)在這樣就非常靈活了,修改信道、修改端口甚至轉(zhuǎn)移服務(wù)端的位置只需要重新調(diào)整配置文件即可。

      23.3.4  使用接口降低耦合

      讀者首先要明確一點(diǎn),客戶端調(diào)用的遠(yuǎn)程方法是在服務(wù)端執(zhí)行的。如下,我們在遠(yuǎn)程對象中增加一個(gè)方法。

      public void HelloWorld()

      {

          Console.WriteLine("編程快樂");

      }

      重新編譯服務(wù)端和客戶端,運(yùn)行客戶端可以看到服務(wù)端控制臺程序上輸出了“編程快樂”字樣,如圖23-24所示。

      文本框:  
圖23-24  遠(yuǎn)程對象在服務(wù)端執(zhí)行

那么問題就來了,既然遠(yuǎn)程對象是在服務(wù)端執(zhí)行的,客戶端為什么要引用遠(yuǎn)程對象呢?假設(shè)我們的報(bào)表系統(tǒng)是使用.NET Remoting開發(fā)的,難道要把核心DLL也公布給客戶嗎(要知道.NET應(yīng)用程序是很容易被反編譯得到“源代碼”的)?其實(shí),客戶端只需要得到遠(yuǎn)程對象的“描述”,知道遠(yuǎn)程對象的類型以及成員定義,讓客戶端代碼能編譯通過即可。具體方法是什么,怎么實(shí)現(xiàn),客戶端并不關(guān)心。

      那么,怎么構(gòu)建這個(gè)供客戶端使用的殼子呢?有兩種方法。

      ·      直接使用工具比如soapsuds.exe來生成。

      ·      使用基于接口的編程方法。

      由于篇幅關(guān)系,在這里我們僅僅介紹第二種方法的實(shí)現(xiàn):

      1.新建一個(gè)類庫項(xiàng)目ITestRemoteObject,這個(gè)類庫是前面TestRemoteObject的接口(Interface),因此以字母I開頭。

      2.打開TestRemoteObject下的RemoteObject.cs,把鼠標(biāo)放在MyObject類上單擊右鍵,選擇“重構(gòu)”→“提取接口”,如圖23-25所示。

      單擊“全選”按鈕選中所有成員,單擊“確定”按鈕??梢钥吹絋estRemoteObject類庫下面多了一個(gè)cs文件,如圖23-26所示。

                       

                                                     圖23-25  提取接口                                                    圖23-26  自動生成的接口

      IMyObject就是MyObject類對應(yīng)的接口。打開這個(gè)文件可以看到接口其實(shí)就是對類成員的定義,沒有實(shí)際的實(shí)現(xiàn)。

      using System;

      namespace TestRemoteObject

      {

          interface IMyObject

          {

              int Add(int a, int b);

              string[] GetData();

              void HelloWorld();

          }

      }

      對這個(gè)接口我們要進(jìn)行一些改動:

      ·      要讓接口能被外部調(diào)用,需要把接口加上公有訪問修飾符。

      ·      系統(tǒng)自動以程序集的名字作為命名空間的命名,我們還是改回原來的RemoteObject。

      using System;

      namespace RemoteObject

      {

          public interface IMyObject

          {

              int Add(int a, int b);

              string[] GetData();

              void HelloWorld();

          }

      }

      3.現(xiàn)在這個(gè)接口在遠(yuǎn)程對象文件中,我們需要把它移動到ITestRemoteObject中,直接點(diǎn)擊文件,Ctrl+X(剪切)、CTRL+V(粘貼)即可。

      4.回頭看MyObject文件:

      public class MyObject : MarshalByRefObject, TestRemoteObject.IMyObject

      系統(tǒng)自動讓它繼承了TestRemoteObject.IMyObject,剛才我們把TestRemoteObject修改成了RemoteObject,現(xiàn)在這里也需要同樣修改。

      既然讓類實(shí)現(xiàn)接口,那么就需要讓TestRemoteObject項(xiàng)目引用ITestRemoteObject項(xiàng)目。右鍵單擊TestRemoteObject項(xiàng)目,選擇添加引用,在項(xiàng)目選項(xiàng)卡中找到ITestRemoteObject項(xiàng)目,單擊“確定”按鈕即可。

      現(xiàn)在兩個(gè)項(xiàng)目的結(jié)構(gòu)應(yīng)該如圖23-27所示。

      你可能會問,接口僅僅是對類的一個(gè)定義嗎?不僅僅是這樣,接口還對類有約束力,如果你修改了接口也一定要修改“實(shí)現(xiàn)”。如果你在接口中新加入一個(gè)Test()的方法,而不修改“實(shí)現(xiàn)”,編譯程序會得到編譯錯(cuò)誤,如圖23-28所示。

                    

                   圖23-27  基于接口的編程                                          圖23-28  類需要實(shí)現(xiàn)接口的成員

      5.現(xiàn)在,我們的客戶端就可以引用和使用接口,而不是直接引用和使用遠(yuǎn)程對象了。首先右鍵單擊TestWeb網(wǎng)站,選擇屬性頁。在引用頁找到原來的遠(yuǎn)程對象TestRemoteObject,刪除它的引用,并添加ITestRemoteObject的引用,如圖23-29所示。

      圖23-29  修改網(wǎng)站項(xiàng)目的引用

      查找替換Remoting.aspx.cs中的所有RemoteObject. MyObject為RemoteObject.IMyObject,比如:

      RemoteObject.IMyObject mo = (RemoteObject.IMyObject)Activator.

      GetObject(typeof(RemoteObject.IMyObject), ConfigurationManager.

      AppSettings["TCPChannel"]);

      mo.HelloWorld();

      6.重新編譯解決方案,先后運(yùn)行服務(wù)端和客戶端,效果和原來的沒有什么不同。但是,這樣的方式更靈活了,或者說耦合更低了。為什么這樣說呢?因?yàn)?,現(xiàn)在如果希望在服務(wù)端的實(shí)現(xiàn)中做什么改動的話,不需要重新編譯和部署客戶端程序。

      23.3.5  使用Windows服務(wù)承載遠(yuǎn)程對象

      現(xiàn)在的程序看似很完美,但是要想真正應(yīng)用還有一些問題。我們的服務(wù)端是一個(gè)控制臺應(yīng)用程序,如果在服務(wù)器上需要有10個(gè)Remoting的服務(wù)端,那么我們服務(wù)器重啟動后也需要重啟動這10個(gè)程序嗎?讀者可能會說可以把它們加入開始菜單的啟動中讓程序自動啟動。但是你有沒有想過,在登錄到服務(wù)器進(jìn)行維護(hù)的時(shí)候很容易不小心把控制臺程序關(guān)閉了,而且關(guān)閉之后還不知道。

      要想解決這個(gè)問題就需要使用一種后臺式的程序來作為服務(wù)端,Windows服務(wù)正好可以滿足這個(gè)要求,而且還可以設(shè)置Windows服務(wù)自動啟動。使用VS 2005創(chuàng)建.NET的Windows服務(wù)非常簡單,下面我們一起來實(shí)現(xiàn)Windows服務(wù)版本的Remoting服務(wù)端。

      1.創(chuàng)建一個(gè)新的Windows服務(wù)項(xiàng)目TestRemotingService,如圖23-30所示。

      圖23-30  創(chuàng)建新的Windows服務(wù)項(xiàng)目

      2.打開Service1代碼視圖,找到OnStart部分,加入代碼。

      protected override void OnStart(string[] args)

      {

      System.Runtime.Remoting.RemotingConfiguration.Configure(AppDomain.CurrentDomain.

      BaseDirectory + "TestRemotingService.exe.config", false);

      }

      這句代碼實(shí)現(xiàn)在Windows服務(wù)啟動的時(shí)候從Windows服務(wù)安裝目錄所在的配置文件加載Remoting配置,然后把先前控制臺服務(wù)端的配置文件復(fù)制過來。

      現(xiàn)在這個(gè)Windows服務(wù)是Remoting的服務(wù)端,因此也別忘記添加對TestRemoteObject遠(yuǎn)程對象的引用。

      3.切換到Service1的設(shè)計(jì)視圖,在空白處右鍵單擊,然后選擇“添加安裝程序”選項(xiàng)。如圖23-31所示。

      圖23-31  添加服務(wù)安裝程序

      4.打開系統(tǒng)自動生成的ProjectInstaller.cs,如圖23-32所示,可以看到頁面上有兩個(gè)組件。

      圖23-32  服務(wù)安裝程序

      單擊serviceProcessInstaller1組件,觀察屬性窗口,如圖23-33所示。

      在這里我們把Account屬性設(shè)置為LocalSystem,作為服務(wù)的賬戶類型。然后單擊serviceInstaller1組件,觀察屬性窗口,如圖23-34所示。

                       

                            圖23-33  ServiceProcessInstaller組件                                          圖23-34  ServiceInstaller組件

      在這里可以設(shè)置服務(wù)友好名、服務(wù)的描述、服務(wù)名和啟動方式。只需要把StartType設(shè)置為Automatic,服務(wù)就能在系統(tǒng)重新啟動后自動啟動。

      5.現(xiàn)在就可以安裝服務(wù)了,單擊“開始”菜單→“所有程序”→Microsoft Visual Studio 2005→Visual Studio Tools→“Visual Studio 2005命令行提示”,如圖23-35所示,使用installutil程序來安裝Windows服務(wù)。

      圖23-35  使用installutil工具安裝Windows服務(wù)

      如果你覺得輸入exe所在路徑太麻煩,可以直接打開文件夾把exe文件拖入命令行窗口。卸載服務(wù)使用–u參數(shù)。

      installutil -u Windows服務(wù)exe所在路徑

      6.執(zhí)行“我的電腦右鍵”→“管理”→“服務(wù)和應(yīng)用程序”→“服務(wù)”命令。如圖23-36所示,可以在列表中找到我們的服務(wù)。

      圖23-36  服務(wù)已經(jīng)安裝成功

      查看這個(gè)服務(wù)的屬性,如圖23-37所示。

      圖23-37  Windows服務(wù)的屬性

      7.如果程序?qū)懙臎]有什么問題的話(其實(shí)我們只寫了一行代碼),服務(wù)應(yīng)該能正常啟動,然后可以打開網(wǎng)站進(jìn)行測試。

      注意:由于安全問題,必須為Windows服務(wù)指定一個(gè)有效賬戶(Account=User)才能使用IPC信道,在這里就不詳細(xì)敘述了。

      除了使用Windows服務(wù)承載遠(yuǎn)程對象外,還可以使用IIS。不過需要注意,使用IIS承載遠(yuǎn)程對象只能在HTTP信道上通信,好處在于可以使用IIS來進(jìn)行安全管理。需要說的是,HTTP方式的Remoting效率非常低(甚至不如Web Service),因此不推薦。具體實(shí)現(xiàn)IIS部署Remoting的方法在這里就不說明了。

      23.3.6  異步操作

      在介紹Web服務(wù)的時(shí)候,我們介紹了異步調(diào)用Web服務(wù)的操作,在這里我們將介紹如何異步調(diào)用遠(yuǎn)程對象的方法。

      1.首先在遠(yuǎn)程對象中加一個(gè)耗時(shí)2秒的方法。

      public string LongWork()

      {

          System.Threading.Thread.Sleep(2000);

          return "編程快樂";

      }

      別忘記同時(shí)更新接口。

      using System;

      namespace RemoteObject

      {

          public interface IMyObject

          {

              int Add(int a, int b);

              string[] GetData();

              void HelloWorld();

              string LongWork();

          }

      }

      2.在客戶端RemotingTest.asp上添加一個(gè)按鈕,按鈕的單擊事件處理方法如下:

      protected void btn_AsyncInvoke_Click(object sender, EventArgs e)

      {

          sw = new System.Diagnostics.Stopwatch();

          sw.Start();

          RemoteObject.IMyObject mo = (RemoteObject.IMyObject)

          Activator.GetObject(typeof(RemoteObject.IMyObject), ConfigurationManager.

          AppSettings["TCPChannel"]);

          MyDelegate md = new MyDelegate(mo.LongWork);

          AsyncCallback ac = new AsyncCallback(this.CallBack);

          IAsyncResult Iar = md.BeginInvoke(ac, null);

          System.Threading.Thread.Sleep(1000);

      }

      在這里使用了兩個(gè)私有變量,一個(gè)是用于Stopwatch,另外一個(gè)是方法的代理,在Page_Load上        添加。

      private delegate string MyDelegate();

      private System.Diagnostics.Stopwatch sw;

      在調(diào)用了異步方法后線程休息了1秒,異步方法完成之后會調(diào)用回調(diào)方法。

      public void CallBack(IAsyncResult Iar)

      {

          if (Iar.IsCompleted)

          {

              Response.Write("異步調(diào)用<br/>");

              Response.Write(string.Format("花費(fèi)時(shí)間:{0}毫秒<br/>", sw.

              ElapsedMilliseconds));

          }

      }

      3.由于方法是異步調(diào)用的,方法執(zhí)行2秒,我們當(dāng)前的按鈕單擊處理事件占用1秒,總共占用的時(shí)間也是2秒,如圖23-38所示。

      圖23-38  異步調(diào)用方法

      異步調(diào)用遠(yuǎn)程對象的方法和異步調(diào)用本地對象的方法其實(shí)差不多,在這里就不詳述了。

        本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多