首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 與 .NET:從細節出發設計良好的分散式框架(一)─ 通用介面 AOP 與 DTO 設計

     編輯:關於C#

背景:系統整合困境

資訊系統日益增多,不同系統常採用不同技術、平台開發,缺乏統一規劃、資料標準與呼叫介面,導致系統交互困難。常見做法是讓開發人員提供 Web Service 或 HTTP 介面,但需求頻繁變更、代碼持續迭代,應用端增加導致資料格式、特殊處理、DTO 設計不斷變動。使用 .NET 的開發者深知:Web Service 更新需同步更新應用端代理類,產生強依賴。首要細節問題:解決服務端與應用端強依賴,設計通用介面規範。

技術要點

  1. AOP(切面導向程式設計)
  2. JavaScriptSerializer(JSON 序列化)
  3. DTO 設計(資料傳輸物件)

實作:通用介面回傳類型

IAOPResult 介面定義

public interface IAOPResult {
  int ResultNo { get; }                 // 回傳代碼:<0 異常,0 成功,>0 提示
  string ResultDescription { get; }     // 描述訊息
  object ResultAttachObject { get; }    // 附加資訊(物件/陣列)
  IAOPResult InnerAOPResult { get; }    // 內部 AOP 結果
  bool IsSuccess { get; }               // ResultNo == 0
  bool IsNotSuccess { get; }            // ResultNo != 0
  bool IsFailed { get; }                // ResultNo < 0
  bool IsPassedButFailed { get; }       // ResultNo > 0
  IAOPResult ThrowErrorOnFailed();      // 失敗時拋出異常
}

AOPResult 實作與 Web Service 應用範例

[Serializable]
public class AOPResult : IAOPResult { ... }

[WebMethod(Description = "檢查購物車中的禮品")]
[SoapHeader("header")]
public AOPResult CheckGiftForCart(List<CartLineDTO> carlist, bool returnflag) {
  ValidateAuthentication();
  return (AOPResult)CartGiftCenter.GiftService.CheckGiftForCart(carlist, returnflag);
}

[WebMethod(Description = "獲取所有的贈品信息")]
[SoapHeader("header")]
public AOPResult GetGiftList() {
  ValidateAuthentication();
  var result = (AOPResult)CartGiftCenter.GiftService.GetModelList();
  if (result.IsSuccess) {
    result.ResultAttachObject = result.ResultAttachObject.ObjectToJson();
  }
  return result;
}

[WebMethod(Description = "根據Id獲得組信息")]
[SoapHeader("header")]
public AOPResult GetGroupInfoByID(int Id) {
  ValidateAuthentication();
  var result = (AOPResult)CartGiftCenter.GroupService.GetModelInfoById(Id);
  if (result.IsSuccess) {
    var resultobj = result.ResultAttachObject as GiftGroup;
    result.ResultAttachObject = new GroupLineDTO {
      GroupId = (int)resultobj.GroupId
    }.ObjectToJson();
  }
  return result;
}

所有服務方法採用相同回傳類型 AOPResult,可裝載物件或陣列。物件需序列化為 JSON:

public static class JsonExtensions {
  private static JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
  public static string ObjectToJson(this object obj) {
    return javaScriptSerializer.Serialize(obj);
  }
  public static T JsonToObject<T>(this string json) {
    if (string.IsNullOrEmpty(json)) return default(T);
    return javaScriptSerializer.Deserialize<T>(json);
  }
}

優點分析

  • 統一服務協議:雙方共同標準,應用端不再完全依賴代理類。服務端變更不直接影響應用端。例:應用 A 只需欄位 C,服務端新增欄位 D 重新建置,A 只要 C 存在且結構不變即無需重建。
  • 統一切面程式設計:利用 AOP 可對服務回饋統一操作、檢查(如系統認證、內容過濾)。推薦參考:AOP 實務文章。

簡易 AOP 輔助類

public class AspectF {
  internal Action<Action> Chain = null;
  internal Delegate WorkDelegate;
  public void Do(Action work) { ... }
  public TReturnType Return<TReturnType>(Func<TReturnType> work) { ... }
  public static AspectF Define { get { return new AspectF(); } }
  public AspectF Combine(Action<Action> newAspectDelegate) { ... }
  public static void Retry(int retryDuration, int retryCount, Action<Exception> errorHandler, Action retryFaild, Action work) { ... }
}

public static class AspectExtensions {
  public static AspectF Delay(this AspectF aspect, int milliseconds) { ... }
  public static AspectF MustBeNonNull(this AspectF aspect, params object[] args) { ... }
  public static AspectF MustBeNonDefault<T>(this AspectF aspect, params T[] args) where T : IComparable { ... }
  public static AspectF WhenTrue(this AspectF aspect, params Func<bool>[] conditions) { ... }
  public static AspectF RunAsync(this AspectF aspect, Action completeCallback) { ... }
  public static AspectF RunAsync(this AspectF aspect) { ... }
}

缺點

效能開銷:物件序列化/反序列化、強制轉型、傳統 AOP 反射開銷。但一般專案利大於弊。

DTO 設計考量

DTO(Data Transfer Object)用於遠端呼叫大量傳輸物件。例:資料表 20 欄位,PO 物件 20 屬性,但介面僅需 10 欄位,無需傳輸完整 PO,以 10 屬性 DTO 傳輸。

實際場景需考量:

  • 資料庫通用性前提下,DTO 僅提供 ID 等識別欄位。
  • 依業務場景,應用端需求少可設計冗餘型別甚至直接用 PO。
  • 內網頻寬充足可大方填充;公網專案需考慮呼叫頻率、敏感欄位不放入 DTO。

本篇先止於此,歡迎討論。下章探討利用泛型簡化多資料庫操作。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved