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

WCF 進階:不加服務參考,手寫 ClientBase 代理類呼叫服務

     編輯:關於.NET

習慣在 Visual Studio 「加入服務參考」產生 Proxy 的開發者,往往忽略 WCF 的通道模型本質。其實只要共用服務合約 (Contract),客戶端即可手寫代理類,直接用 ChannelFactory<T> 或繼承 ClientBase<T> 建立通道呼叫服務,完全不需產生庞大的產生代碼與設定檔。本文以簡單算術服務為例,示範雙通道 (HTTP/TCP) 手動呼叫全流程。

共用合約組件

建立 Class Library CommonLib 定義服務合約,伺服端與客戶端同時參考:

[ServiceContract]
public interface ITest {
  [OperationContract] int Add(int a, int b);
  [OperationContract] int Multiply(int a, int b);
  [OperationContract] int GetRandom();
}

伺服端:自託管雙端點

public class MyService : ITest {
  readonly Random _rnd = new Random();
  public int Add(int a, int b) => a + b;
  public int Multiply(int a, int b) => a * b;
  public int GetRandom() => _rnd.Next();
}

static void Main() {
  var host = new ServiceHost(typeof(MyService));
  // HTTP 端點
  host.AddServiceEndpoint(typeof(ITest), new WSHttpBinding(SecurityMode.None), "https://localhost:8900/");
  // TCP 端點
  host.AddServiceEndpoint(typeof(ITest), new NetTcpBinding(SecurityMode.None), "net.tcp://localhost:1700/");
  host.Open();
  Console.WriteLine("服務已啟動,按任意鍵結束...");
  Console.ReadKey();
  host.Close();
}

關鍵差異:不設基底位址、不加 ServiceMetadataBehavior,因為不需產生 WSDL/Proxy。

客戶端方案一:ChannelFactory 直建通道


var httpEp = new EndpointAddress("https://localhost:8900/");
var tcpEp  = new EndpointAddress("net.tcp://localhost:1700/");

void CallHttp() {
  var binding = new WSHttpBinding(SecurityMode.None);
  var factory = new ChannelFactory(binding);
  ITest channel = factory.CreateChannel(httpEp);
  try {
    Console.WriteLine($"Add: {channel.Add(1,2)}");
    Console.WriteLine($"Mul: {channel.Multiply(3,4)}");
    Console.WriteLine($"Rnd: {channel.GetRandom()}");
  } finally {
    ((IClientChannel)channel).Close();
    factory.Close();
  }
}

void CallTcp() {
  var binding = new NetTcpBinding(SecurityMode.None);
  var factory = new ChannelFactory(binding);
  ITest channel = factory.CreateChannel(tcpEp);
  try { /* 同上 */ } finally { ((IClientChannel)channel).Close(); factory.Close(); }
}

客戶端方案二:繼承 ClientBase 封裝強型別 Proxy(推薦)


public class MyClient : ClientBase, ITest {
  public MyClient(Binding binding, EndpointAddress address) : base(binding, address) { }
  public int Add(int a, int b) => Channel.Add(a, b);
  public int Multiply(int a, int b) => Channel.Multiply(a, b);
  public int GetRandom() => Channel.GetRandom();
}

呼叫端極度簡潔:


using (var client = new MyClient(new WSHttpBinding(SecurityMode.None), httpEp)) {
  Console.WriteLine(client.Add(10, 20));
}
using (var client = new MyClient(new NetTcpBinding(SecurityMode.None), tcpEp)) {
  Console.WriteLine(client.Multiply(5, 6));
}

為何雙重實作 ITest?

  • ClientBase<T> 內部已實作通道建立/關閉邏輯,Channel 屬性直接暴露 T 介面。
  • 再次實作 ITest 讓 MyClient 本身成為強型別 Proxy,呼叫端像呼叫本地物件一樣自然。
  • 此模式與 VS 產生的 Proxy 類別結構一致,且無需 app.config 設定端點。

注意事項

  1. 伺服端需以 **系統管理員身分** 執行(HTTP 端點保留 URL ACL)。
  2. Binding 參數 (SecurityMode, ReliableSession 等) 雙方必須一致。
  3. 通道使用完畢務必 Close(),異常時呼叫 Abort() 避免佔用連線。
  4. 若服務有回呼合約,需改用 DuplexChannelFactory。

結語

手寫 Proxy 不僅減少專案依賴、部署檔案,更能深入理解 WCF 通道架構。掌握 ChannelFactory 與 ClientBase 兩種模式,彈性應對無法加入服務參考(如跨平台、動態端點、AOT 編譯)的場景。

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