1. .net Remoting編程-客戶端訂閱服務端事件
第一步:創建共享庫
依次點擊「文件」->「新創建」->「工程」,選擇創建一個c# library,並將其命名為resumeserverlibrary,然後點擊ok按鈕。這將創建一個我們的.net remote客戶端和伺服器端用來通訊的「共享命令集」。
正面是完整的代碼,如果要跳過資料庫訪問部分,可以使用下面的代碼替換resumeloader對象:
public class resumeloader : system.marshalbyrefobject
{
public resumeloader()
{
system.console.writeline("new referance added!");
}
public resume getresumebyuserid(decimal userid)
{
return new resume(1);
}
}
名字空間是對象所需要的。請記住,如果得到system.runtime.remoting.channels.tcp名字空間不存在的信息,請檢查是否象上面的代碼那樣添加了對system.runtime.remoting.dll的引用。
using system;
using system.runtime;
using system.data.sqlclient;
我們為對象使用的名字空間是dotnetremotetest,下面的對象是marshalbyrefobject,在其中我們創建了一個引用和包括伺服器端資料庫操作全部完成所需要的所有工作。
namespace dotnetremotetest
{
public class resumeloader : system.marshalbyrefobject
{
private sqlconnection dbconnection;
public resumeloader()
{
this.dbconnection = new system.data.sqlclient.sqlconnection();
this.dbconnection.connectionstring =
"data source=grimsaado2k;initial catalog=underground;integrated security=sspi;pers" +
"ist security info=true;workstation id=grimsaado2k;packet size=4096";
/*具體的連接字元串會有所不同,這超出了本篇文章的范圍。如果不清楚如何創建一個資料庫連接,請使用這一對象的另一個版本。*/
system.console.writeline("new referance added!");
}
public resume getresumebyuserid(decimal userid)
{
resume resume = new resume();
try
{
dbconnection.open();
sqlcommand cmd = new sqlcommand(
"select resumeid, userid, title, body from resume as theresume where theresume.userid="+ userid +""
, dbconnection
);
sqldatareader areader = cmd.executereader();
if(areader.read())
{
resume.resumeid=areader.getdecimal(0);
resume.userid=areader.getdecimal(1);
resume.title=areader.getstring(2);
resume.body=areader.getstring(3);
}
areader.close();
dbconnection.close();
}
catch(exception x) { resume.title="error:"+x; }
return resume;
}
}
resume需要能夠被串列化,以便能作為被遠程調用的.net remote對象的返回類型,原因是該對象將被轉換為通過網路傳輸的原始數據,然後在網路的另一端再被裝配成一個對象。
該對象非常簡單,為了使本篇文章看起來更簡單,其中的構造器甚至使用預設的內容初始化其中的一些域。
[serializable]
public class resume
{
private decimal resumeid, userid;
private string body, title;
public resume(decimal resumeid)
{
this.resumeid=resumeid;
this.userid=1;
this.body="this is the default body of the resume";
this.title="this is the default title";
}
public decimal resumeid
{
get { return resumeid; }
set { this.resumeid=value; }
}
public decimal userid
{
get { return userid; }
set { this.userid=value; }
}
public string body
{
get { return body; }
set { this.body=value;}
}
public string title
{
get { return title; }
set { this.title=value; }
}
}//resume對象結束
}//dotnetremotetest名字空間結束
編譯創建的工程,就會得到一個dll文件,並可以在其他的工程中使用它。
第二步:創建server對象
有幾種方法可以創建server對象,最直觀的方法是下面的方法:在visual studio.net中,依次點擊「文件」->「新創建」->「工程」,選擇創建一個「command line application」(命令行應用程序),並將它命名為resumesuperserver。
最最重要的是,我們需要添加對剛才在第一步中所創建的dll文件的應用,該應用程序才能正確地運行。依次點擊「工程」->「添加引用」,然後通過點擊「瀏覽」按鈕添加一個對在第一步中所創建的dll文件的引用。
為了使用.net remote功能,必須通過選擇「工程」->「添加引用」,添加對dll文件的引用。在.net標簽中選擇system.runtime.remoting.dll,然後點擊「ok」按鈕。然後,需要象我們在第一步中那樣添加對system.runtime.remoting.dll的引用。
下面的對象相當的簡單和直觀,我將就真正與.net remoting相關的3行代碼中的每一行進行解釋。
tcpserverchannel是.net remoting支持的二種信道類型中的一種,它將設置我們希望我們的對象對來自哪一個埠的請求進行回應,channelservices.registerchannel將把該埠號與操作系統中的tcp/ip棧綁定。
tcpserverchannel channel = new tcpserverchannel(9932);
channelservices.registerchannel(channel);
另一種可以設置的信道類型是http,只要簡單地使用system.runtime.remoting.channels.http名字空間中的httpserverchannel對象即可搞定。使用http和tcp信道之間的區別可以簡單的歸結為:如果應用程序是在區域網上運行,則最好使用tcp信道,因為它的性能要好於http信道;如果應用程序是在互聯網上運行,則有時候根據防火牆的配置,http是唯一的選擇。需要記住的是,如果使用了防火牆軟體,則防火牆應該配置成允許tcp數據流量通過你為對象選擇的埠。
remotingconfiguration.registerwellknownservicetype(typeof(resumeloader),
"resumeloader", wellknownobjectmode.singlecall);
這行代碼設置了服務中的一些參數和把欲使用的對象名字與遠程對象進行綁定,第一個參數是綁定的對象,第二個參數是tcp或http信道中遠程對象名字的字元串,第三個參數讓容器知道,當有對對象的請求傳來時,應該如何處理對象。盡管wellknownobjectmode.single對所有的調用者使用一個對象的實例,但它為每個客戶生成這個對象的一個實例。
完整的對象代碼如下所示:
using system;
using system.runtime;
using system.runtime.remoting;
using system.runtime.remoting.channels;
using system.runtime.remoting.channels.tcp;
using system.data.sqlclient;
using dotnetremotetest;
namespace resumeserverserver
{
public class resumesuperserver
{
public static void main(string[] args)
{
tcpserverchannel channel = new tcpserverchannel(9932);
channelservices.registerchannel(channel);
remotingconfiguration.registerwellknownservicetype(typeof(resumeloader),
"resumeloader", wellknownobjectmode.singlecall);
system.console.writeline("press any key");
system.console.readline();
}
}
}
編譯這一程序並注意生成的.exe文件的位置。
第三步:創建remote客戶端程序
resumeclinet是我們為對在上面創建的resumesuperserver遠和對象進行測試而創建的。要創建這一工程,可以依次點擊「文件」->「創建」->「工程」,然後選擇創建一個console application類型、名字為resumeclient的工程名。象在第二步中那樣,我們需要添加對在第一步中創建的dll文件和system.runtime.remoting dll的引用。
下面的代碼中有二行對於.net remoting而言是特別重要的。第一行創建了一個tcp客戶端信道,該信道並不是綁定在一個埠上的;第二行獲取了一個對遠程的resumeloader對象的引用。activator.getobject方法返回一個對象類型的值,我們隨後會將它返回的值賦予resumeloader。我們傳給它的參數與在伺服器工程中傳遞給remotingconfiguration的參數非常地相似,第一個參數是對象類型的,第二個參數是遠程對象的uri。
channelservices.registerchannel(new tcpclientchannel());
resumeloader loader = (resumeloader)activator.getobject(
typeof(resumeloader), "tcp://localhost:9932/resumeloader");
resumeclient的全部代碼如下所示:
using system;
using system.runtime.remoting;
using system.runtime.remoting.channels;
using system.runtime.remoting.channels.tcp;
using dotnetremotetest;
namespace resumeclient
{
public class resumeclient
{
public static void main(string[] args)
{
channelservices.registerchannel(new tcpclientchannel());
resumeloader loader = (resumeloader)activator.getobject(
typeof(resumeserver), "tcp://localhost:9932/resumeloader");
if(rs==null)
{ console.writeline("unable to get remote referance"); }
else
{
resume resume = loader.getresumebyuserid(1);
console.writeline("resumeid:"+ resume.resumeid);
console.writeline("userid:"+ resume.userid);
console.writeline("title:"+ resume.title);
console.writeline("body:"+ resume.body);
}
console.readline();//在能夠看到結果前不讓窗口關閉
}//end of main method
}//end of resumeclient object
}//end of resumeclientnamespace
測試
在資料庫中創建一個具有如下結構的表:
table name-resume
resumeid, numeric (autonumber)
userid, numeric
title, char(30)
body, text
雙擊我們在第二步中創建的server.exe,然後雙擊在第三步中創建的client可執行文件。如果一切正常的話,我們應該能夠看到資料庫中resumeid的值為1的記錄行。
總之,.net remoting使用起來很簡單,而且為處理區域網甚至互聯網范圍內的資源提供了一個絕佳的方法。