Windows Communication Foundation (WCF) 的核心哲學是「契約優先、介面導向」。與傳統 ASMX Web Service 或 .NET Remoting 不同,WCF 強制將服務契約(介面)與實作分離,並透過標準化的訊息交換實現真正的跨平台、跨傳輸協定互通。本文以逐步建置專案的方式,完整示範從定義契約、實作服務、自我宿主、建立客戶端代理,到共用複雜資料型別(Model)的端到端開發流程。
| 專案名稱 | 類型 | 職責 | 關鍵參考 |
|---|---|---|---|
| Contracts | Class Library | 定義服務契約介面 [ServiceContract]、資料契約 [DataContract] | System.ServiceModel |
| Services | Class Library | 實作服務契約介面 | Contracts, System.ServiceModel |
| Host | Console Application | 服務宿主,啟動 ServiceHost | Contracts, Services, System.ServiceModel |
| Client | Console Application | 消費服務,建立 ChannelFactory/ClientBase 代理 | Contracts, System.ServiceModel |




// Contracts/IHelloContract.cs
using System.ServiceModel;
namespace Contracts
{
[ServiceContract]
public interface IHelloContract
{
[OperationContract]
string HelloWorld();
}
}




// Services/HelloService.cs
using Contracts;
using System.ServiceModel;
namespace Services
{
public class HelloService : IHelloContract
{
public string HelloWorld()
{
return "Hello from WCF Service!";
}
}
}




// Host/Program.cs
using Services;
using Contracts;
using System.ServiceModel;
namespace Host
{
class Program
{
static void Main(string[] args)
{
// 完全以程式碼配置(亦可用 app.config)
var binding = new NetTcpBinding();
var address = new EndpointAddress("net.tcp://localhost:81/HelloService");
using (var host = new ServiceHost(typeof(HelloService), new Uri[] { }))
{
host.AddServiceEndpoint(typeof(IHelloContract), binding, address);
host.Open();
Console.WriteLine("服務已啟動,按 Enter 結束...");
Console.ReadLine();
}
}
}
}




// Client/HelloServiceClient.cs
using Contracts;
using System.ServiceModel;
namespace Client
{
// 繼承 ClientBase<TChannel> 並實作契約介面,即為型別安全的客戶端代理
public class HelloServiceClient : ClientBase<IHelloContract>, IHelloContract
{
public HelloServiceClient(Binding binding, EndpointAddress address)
: base(binding, address) { }
public string HelloWorld()
{
return Channel.HelloWorld(); // 委派給內部 Channel
}
}
}



// Client/Program.cs
using System;
using System.ServiceModel;
using Contracts;
namespace Client
{
class Program
{
static void Main(string[] args)
{
var binding = new NetTcpBinding();
var address = new EndpointAddress("net.tcp://localhost:81/HelloService");
var proxy = new HelloServiceClient(binding, address);
Console.WriteLine(proxy.HelloWorld()); // 輸出: Hello from WCF Service!
Console.ReadLine();
}
}
}
WCF 最大優勢之一:複雜型別可在服務端與客戶端共用同一組件,避免 Web Service 時代「Proxy 生成的型別與原始型別不同」的問題。



// Model/Employee.cs
using System.Runtime.Serialization;
namespace Model
{
[DataContract]
public class Employee
{
[DataMember] public int ID { get; set; }
[DataMember] public string Name { get; set; }
[DataMember] public string Department { get; set; }
public override string ToString() => $"ID:{ID}, Name:{Name}, Dept:{Department}";
}
}


// Contracts/IHelloContract.cs (修改後)
[ServiceContract]
public interface IHelloContract
{
[OperationContract] string HelloWorld();
[OperationContract] Employee GetEmployee(); // 新增
}


// Services/HelloService.cs (修改後)
public class HelloService : IHelloContract
{
public string HelloWorld() => "Hello from WCF Service!";
public Employee GetEmployee()
{
return new Employee { ID = 1001, Name = "Terry", Department = "RD" };
}
}

// Client/HelloServiceClient.cs (修改代理)
public class HelloServiceClient : ClientBase<IHelloContract>, IHelloContract
{
public HelloServiceClient(Binding binding, EndpointAddress address)
: base(binding, address) { }
public string HelloWorld() => Channel.HelloWorld();
public Employee GetEmployee() => Channel.GetEmployee(); // 直接回傳共用 Model.Employee
}
// Client/Program.cs (呼叫新操作)
static void Main(string[] args)
{
var binding = new NetTcpBinding();
var address = new EndpointAddress("net.tcp://localhost:81/HelloService");
var proxy = new HelloServiceClient(binding, address);
Console.WriteLine(proxy.HelloWorld());
var emp = proxy.GetEmployee();
Console.WriteLine(emp); // 輸出: ID:1001, Name:Terry, Dept:RD
Console.ReadLine();
}

| 概念 | 說明 | 關鍵屬性/基類 |
|---|---|---|
| 服務契約 | 定義服務暴露的操作 | [ServiceContract], [OperationContract] |
| 資料契約 | 定義跨邊界傳遞的資料結構 | [DataContract], [DataMember] |
| 端點 | Address + Binding + Contract | EndpointAddress, Binding, Contract |
| 客戶端代理 | 型別安全的呼叫包裝器 | 繼承 ClientBase<T> 並實作 T |
| 型別共用 | 服務/客戶端引用同一 Model 組件 | 無需產生 Proxy,直接使用原始型別 |
app.config/web.config,利用 ConfigurationChannelFactory 動態載入,避免重新編譯。Task<T> 非同步操作契約,搭配 ChannelFactory<T> 建立非同步代理。IErrorHandler 統一將例外轉為 FaultException<TDetail> 回傳,避免通道進入 Faulted 狀態。透過契約優先、介面導向、型別共用,WCF 讓分散式系統開發回歸強型別、編譯期檢查的軌道,是企業級整合的堅實基石。