http://www.cnblogs.com/sofire/archive/2011/07/26/2117004.html
2010年,在企業工作的我開始意識到,“開發”與“業務”之間的沖突。一個系統開發員想要完美的展現一塊功能的業務,這是一件難度較高的事情。精通業務的人,一般是直接的使用者。而一名開發員,僅僅在 DEBUG 時才會使用。這也突兀了一個問題:如何讓開發與業務并行?
這是一個很糾結的問題。兩個結論:要麼讓開發員熟悉業務,要麼讓業務員熟悉開發。同樣,也是一個很無語的結果。
平台化系統迎應而生。這是去年的思想,在今年又發生了許多變化,是以将當時的想法寫下來下,一是分享,二是記錄,三是總結。
由于是企業資訊化系統,是以當時直接選擇了 .NET 3.5。後來更新到了 4.0。(最近,新版本縮水成了2.0囧~~)。
架構圖(請多指教^.^):

·〉業務擴充卡
業務擴充卡可由一個或多個組成。該擴充卡服務公開兩個服務。
1、業務層服務。
業務層可以通過連接配接到“業務擴充卡”進行注冊。将自身的“公共位址”注冊給服務層,并且注冊自己所對應的“應用程式名”。這有點像這樣:
/// <summary> 業務伺服器的注冊資訊。
/// </summary>
[Serializable]
public class RegisterInfo
{
protected string _BusinessID;
public string BusinessID
{
get
{
return this._BusinessID;
}
}
protected string _ApplicationName;
public string ApplicationName
{
get
{
return this._ApplicationName;
}
}
protected string _PrivateIP;
public string PrivateIP
{
get
{
return this._PrivateIP;
}
}
protected string _PublicIP;
public string PublicIP
{
get
{
return this._PublicIP;
}
}
protected string _AddressFormat;
public string AddressFormat
{
get
{
return this._AddressFormat;
}
}
public RegisterInfo(string bussineID, string applicationName, string privateIP, string publicIP)
{
this._BusinessID = bussineID;
this._ApplicationName = applicationName;
this._PrivateIP = privateIP;
this._PublicIP = publicIP;
}
public void SetAddressFormat(string address)
{
this._AddressFormat = address.Replace("localhost", "{0}");
}
}
業務層在向往适配層注冊服務時,需要提供自己的“客戶層應用程式名”,自己的“内外網位址”。這樣,适配層在接收到客戶層的申請時,便可以将注冊的“連接配接位址”告訴客戶層。
這樣做的目的在于:保護實際業務的操作接口(雖然也是公開接口,但是用戶端并不知道如何連接配接他,隻能通過賬号密碼驗證後,業務層發送過來的位址,用戶端才可以連接配接)。
當然更重要的是,還可以實作一個應用多個“服務接口”,這樣在分布式應用中是最有效緩解伺服器壓力的方法之一。
業務層需要注冊資訊已經确認了,那麼便是将服務契約(适配層實作)。
IRegisterContract.cs
/// <summary> 注冊擴充卡的契約。
/// </summary>
[ServiceContract(CallbackContract = typeof(IRegisterCallback))]
public interface IRegisterContract
{
/// <summary> 将業務伺服器注冊到适配伺服器。
/// </summary>
[OperationContract]
Result Register(RegisterInfo info);
[OperationContract(IsOneWay = true)]
void FromBusinessPing(object arg);
}
Callback契約如下(業務層實作):
IRegisterCallback.cs
/// <summary> 注冊擴充卡的回調契約。
/// </summary>
public interface IRegisterCallback
{
/// <summary> 當擴充卡接收登入驗證時的回調函數。
/// </summary>
[OperationContract]
Result ClientLogin(string uid, string pwd);
/// <summary> 激活業務伺服器的狀态。
/// </summary>
[OperationContract(IsOneWay = true)]
void FromAdapterPing(PingCommand command, object arg);
}
這兩個接口用于業務層與适配層之間的會話。每當有一個新的用戶端連接配接到适配層時,适配層會向其索要登入憑證,然後轉發給對應的應用名的業務層。當業務層校驗成功,适配層才會将這個“隐藏于公衆”的位址抛給用戶端。IRegisterContract.FromBusinessPing 是适配層接收到業務層的“激活測試”,業務層要告訴适配層:“我正在運作,可以将客戶給我”。IRegisterCallback.FromAdapterPing 也是同樣的道理。這樣雙方互 PING,可以確定業務層和适配層的線上情況。
當然,這麼繁瑣的“雙方互PING”,還有一個更加重要的作用。
PingCommand.cs
/// <summary> 表示适配伺服器發送至業務伺服器的指令。
/// </summary>
public enum PingCommand
{
/// <summary> 表示這是一個普通的指令。
/// </summary>
None,
/// <summary> 表示這是一個業務伺服器關閉的指令。
/// </summary>
Close,
/// <summary> 表示這是一個業務伺服器更新的指令。
/// </summary>
Update,
}
通過上面的代碼,園友便可以發現,在互動會話的過程中,可以做到“一方斷線,多方支援”。而當業務層分布在10台不同的電腦上,更新業務層也是一個頭疼的問題。是以,這個問題可以交給适配層來完成。适配層隻要檢測到本地“業務層”或“客戶層”應用程式有版本變化,便會主動(客戶層是被動)通知對方更新要求。這樣客戶層和業務層的更新便可以完美解決。
至此,業務層與适配層之間的互動,已經簡單的告訴大家了。
2、客戶層服務
我不知道先上代碼會不會影響大家閱讀,但是我認為閱讀代碼,比閱讀文章更有效,更能吸收。客戶層的契約如下:
ILoginContract.cs
/// <summary> 客戶層登入契約。
/// </summary>
[ServiceContract]
public interface ILoginContract
{
/// <summary> 擷取目前伺服器的所有業務應用系統。
/// </summary>
string[] Applications { [OperationContract] get; }
/// <summary> 指定應用名以及網絡,登入伺服器。如果登入成功,則傳回一個業務伺服器的通路位址。
/// </summary>
[OperationContract]
ClientLoginResult ClientLogin(string applicationName, bool privateNetwork, string uid, string pwd);
/// <summary> [登入限制] - 擷取目前用戶端的版本。
/// </summary>
string ClientVersion { [OperationContract] get; }
/// <summary> [登入限制] - 讀取目前最新版本的用戶端壓縮包流的總長度。
/// </summary>
int ClientArchiveLength { [OperationContract]get; }
/// <summary> [登入限制] - 讀取目前最新版本的用戶端壓縮包。
/// </summary>
[OperationContract]
byte[] ReadClientArchive(int index);
/// <summary> [登入限制] - 擷取目前業務應用系統的版本。
/// </summary>
string ApplicationVersion { [OperationContract] get; }
/// <summary> [登入限制] - 讀取目前最新版本的業務應用系統壓縮包流的總長度。
/// </summary>
int ApplicationArchiveLength { [OperationContract]get; }
/// <summary> [登入限制] - 讀取目前最新版本的業務應用系統壓縮包。
/// </summary>
[OperationContract]
byte[] ReadApplicationArchive(int index);
}
"Applications"屬性是用于告訴用戶端,我(适配層)擁有多少個“終端應用程式”,這樣,用戶端便可以實作“一個登陸界面,N套系統”的理念了。
“ClientLogin()”函數就不用多解釋了,主要是驗證成功後,“ClientLoginResult”的傳回值包含了(“業務層名稱”和“業務層位址”)。
而剩下的東西,便是前面所提到的“一個登陸界面,N套系統”的版本資訊。一個是檢測登陸界面的版本,一個是檢測“業務系統”的版本。
客戶層與适配層之間的互動是不多的,除了登陸憑證,就隻有版本驗證。但是适配層卻起了至關重要。