本文說明如何移轉使用 .NET 遠端處理來使用 Windows Communication Foundation (WCF) 的應用程式。 它會比較這些產品之間的類似概念,然後描述如何在 WCF 中完成數個常見的遠端處理案例。
.NET 遠端處理是僅支援回溯相容性的舊版產品。 這在混合信任環境中並不安全,因為它無法維護客戶端與伺服器之間的個別信任層級。 例如,您不應該將 .NET 遠端端點公開至因特網或不受信任的用戶端。 我們建議將現有的遠端應用程式移轉至較新且更安全的技術。 如果應用程式的設計只使用 HTTP 且為 RESTful,建議您 ASP.NET Web API。 如需詳細資訊,請參閱 ASP.NET Web API。 如果應用程式是以 SOAP 為基礎,或需要非 Http 通訊協定,例如 TCP,我們建議 WCF。
比較 .NET 遠端處理與 WCF
本節會比較 .NET Remoting 的基本構件與其 WCF 等效項目。 我們稍後會使用這些建置組塊,在 WCF 中建立一些常見的用戶端伺服器案例。 下圖摘要說明 .NET 遠端處理與 WCF 之間的主要相似性和差異。
.NET 遠端處理 | WCF(Windows Communication Foundation) | |
---|---|---|
伺服器類型 | 亞綱 MarshalByRefObject |
使用 [ServiceContract] 屬性標記 |
服務作業 | 伺服器類型的公用方法 | 使用 [OperationContract] 屬性標記 |
串行化 |
ISerializable 或 [Serializable] |
DataContractSerializer 或 XmlSerializer |
傳遞的物件 | 依值或參考 | 僅依值 |
錯誤/例外狀況 | 任何可串行化的例外狀況 | FaultContract<TDetail> |
用戶端 Proxy 物件 | 強類型透明代理會由 MarshalByRefObjects 自動建立 | 強型別 Proxy 是使用 ChannelFactory<TChannel 隨選產生> |
平台要求 | 用戶端和伺服器都必須使用 Microsoft OS 和 .NET | 跨平臺 |
訊息格式 | 私人 | 業界標準(例如 SOAP 和 WS-*) |
伺服器實作比較
在 .NET 遠端中建立伺服器
.NET 遠端伺服器類型必須衍生自 MarshalByRefObject,並定義用戶端可以呼叫的方法,如下所示:
public class RemotingServer : MarshalByRefObject
{
public Customer GetCustomer(int customerId) { … }
}
此伺服器類型的公用方法會成為用戶端可用的公用合約。 伺服器公用介面與其實作之間沒有區隔-一種類型會同時處理這兩者。
定義伺服器類型之後,就可以提供給用戶端使用,如下列範例所示:
TcpChannel channel = new TcpChannel(8080);
ChannelServices.RegisterChannel(channel, ensureSecurity : true);
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(RemotingServer),
"RemotingServer",
WellKnownObjectMode.Singleton);
Console.WriteLine("RemotingServer is running. Press ENTER to terminate...");
Console.ReadLine();
有許多方法可將遠端類型當做伺服器使用,包括使用組態檔。 這只是一個範例。
在 WCF 中建立伺服器
WCF 中的對等步驟涉及建立兩種類型:公用「服務合約」和具體實作。 第一個被宣告為用 [ServiceContract] 標示的介面。 用戶端可用的方法會標示為 [OperationContract]:
[ServiceContract]
public interface IWCFServer
{
[OperationContract]
Customer GetCustomer(int customerId);
}
伺服器的實作定義在不同的具體類別中,如下列範例所示:
public class WCFServer : IWCFServer
{
public Customer GetCustomer(int customerId) { … }
}
定義這些類型之後,WCF 伺服器就可供用戶端使用,如下列範例所示:
NetTcpBinding binding = new NetTcpBinding();
Uri baseAddress = new Uri("net.tcp://localhost:8000/wcfserver");
using (ServiceHost serviceHost = new ServiceHost(typeof(WCFServer), baseAddress))
{
serviceHost.AddServiceEndpoint(typeof(IWCFServer), binding, baseAddress);
serviceHost.Open();
Console.WriteLine($"The WCF server is ready at {baseAddress}.");
Console.WriteLine("Press <ENTER> to terminate service...");
Console.WriteLine();
Console.ReadLine();
}
備註
這兩個範例都使用 TCP,以保持它們的相似性。 如需使用 HTTP 的範例,請參閱本主題稍後的案例逐步解說。
有許多方式可以設定和裝載 WCF 服務。 這只是一個稱為「自行架設」的範例。 如需詳細資訊,請參閱下列主題:
用戶端實作比較
在 .NET 遠端處理中建立用戶端
一旦 .NET 遠端伺服器物件可供使用之後,用戶端就可以取用它,如下列範例所示:
TcpChannel channel = new TcpChannel();
ChannelServices.RegisterChannel(channel, ensureSecurity : true);
RemotingServer server = (RemotingServer)Activator.GetObject(
typeof(RemotingServer),
"tcp://localhost:8080/RemotingServer");
RemotingCustomer customer = server.GetCustomer(42);
Console.WriteLine($"Customer {customer.FirstName} {customer.LastName} received.");
從 Activator.GetObject() 傳回的 RemotingServer 實例稱為「透明 Proxy」。它會在用戶端上實作 RemotingServer 類型的公用 API,但所有方法都會呼叫在不同進程或機器中執行的伺服器物件。
在 WCF 中建立用戶端
WCF 中的對等步驟涉及使用通道工廠明確創建代理。 如同遠端處理,代理物件可用來呼叫伺服器上的作業,如下列範例所示:
NetTcpBinding binding = new NetTcpBinding();
String url = "net.tcp://localhost:8000/wcfserver";
EndpointAddress address = new EndpointAddress(url);
ChannelFactory<IWCFServer> channelFactory =
new ChannelFactory<IWCFServer>(binding, address);
IWCFServer server = channelFactory.CreateChannel();
Customer customer = server.GetCustomer(42);
Console.WriteLine($" Customer {customer.FirstName} {customer.LastName} received.");
此範例顯示通道層級的程式設計,因為它與遠端範例最類似。 Visual Studio 中也提供 新增服務參考 方法,可產生程式代碼以簡化用戶端程序設計。 如需詳細資訊,請參閱下列主題:
串行化使用方式
.NET 遠端處理和 WCF 都會使用串行化在用戶端和伺服器之間傳送物件,但兩者在下列重要方面有所不同:
他們會使用不同的串行化程式和慣例來指出要串行化的內容。
.NET Remoting 支援「按引用序列化」,允許在某一層對方法或屬性進行存取,以在另一層上執行跨越安全邊界的代碼。 此功能會公開安全性弱點,而且是遠端端點不應該公開給不受信任用戶端的主要原因之一。
遠端處理所使用的序列化是選擇退出(明確排除不序列化的內容),而 WCF 序列化是選擇加入(明確標記要序列化的成員)。
.NET 遠端處理中的串行化
.NET Remoting 支援兩種方式來在用戶端和伺服器之間進行物件的序列化與反序列化:
依值 – 物件的值會跨階層界限串行化,而該物件的新實例會在另一層上建立。 對新實例之方法或屬性的任何呼叫只會在本機執行,而且不會影響原始物件或階層。
透過參考 – 特殊「物件參考」會跨層序列化。 當某個層與該物件的方法或屬性互動時,訊息會回傳至原始層的原始物件。 參考物件可以向任一方向流動 – 伺服器到用戶端,或客戶端到伺服器。
Remoting 中的 By-value 類型會標示為 [Serializable] 屬性或實作 ISerializable,如下列範例所示:
[Serializable]
public class RemotingCustomer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int CustomerId { get; set; }
}
參考型別衍生自 MarshalByRefObject 類別,如下列範例所示。
public class RemotingCustomerReference : MarshalByRefObject
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int CustomerId { get; set; }
}
了解遠程系統中按參考傳遞的物件的含意非常重要。 如果任何一層(無論是用戶端或伺服器)將傳址物件傳送至另一層,則所有方法呼叫都會在擁有該物件的層上執行。 例如,用戶端在伺服器傳回的按參照物件上呼叫方法時,會在伺服器上執行程式碼。 同樣地,用戶端所提供之參考物件上呼叫方法的伺服器將會在用戶端上執行程序代碼。 基於這個理由,建議只在完全信任的環境中使用 .NET 遠端處理。 將公用 .NET 遠端端點公開給不受信任的用戶端,會使遠端伺服器容易受到攻擊。
WCF 中的串行化
WCF 僅支援依值串行化。 在定義客戶端與伺服器之間交換之類型時,最常見的方式如以下範例所示:
[DataContract]
public class WCFCustomer
{
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
[DataMember]
public int CustomerId { get; set; }
}
[DataContract] 屬性會將此類型識別為可在用戶端和伺服器之間串行化和還原串行化的類型。 [DataMember] 屬性會識別要串行化的個別屬性或字段。
當 WCF 跨層傳送物件時,只會串行化值,並在另一層上建立物件的新實例。 任何與物件值的互動都僅在本地進行, 它們不會像 .NET Remoting 的參考物件那樣與其他層進行通訊。 如需詳細資訊,請參閱 串行化和還原串行化。
例外狀況處理功能
.NET 遠端處理中的例外狀況
遠端伺服器拋出的例外狀況會序列化後傳送至用戶端,並在用戶端本機拋出,就像任何其他例外狀況一樣。 自定義例外狀況可以藉由將 Exception 類型子類別化並標示為 [Serializable] 來建立。 大部分的框架例外狀況已以這種方式標記,允許伺服器丟擲大部分例外狀況、序列化,並在用戶端上重新丟擲。 雖然此設計在開發期間很方便,但伺服器端資訊可能會不小心向用戶端披露。 這是為什麼遠端處理應該只在完全信任的環境中使用的原因之一。
WCF 中的例外狀況和錯誤
WCF 不允許將任意例外狀況類型從伺服器傳回至客戶端,因為它可能會導致不小心的資訊洩漏。 如果服務操作拋出非預期的異常,這會導致在用戶端拋出通用的 FaultException。 此例外狀況不會包含發生問題的原因或位置的任何資訊,而且對於某些應用程式而言,這已足夠。 需要藉由定義錯誤合約,將更豐富的錯誤資訊傳達給客戶端的應用程式。
若要這樣做,請先建立 [DataContract] 類型以攜帶錯誤資訊。
[DataContract]
public class CustomerServiceFault
{
[DataMember]
public string ErrorMessage { get; set; }
[DataMember]
public int CustomerId {get;set;}
}
指定要用於每個服務作業的錯誤合約。
[ServiceContract]
public interface IWCFServer
{
[OperationContract]
[FaultContract(typeof(CustomerServiceFault))]
Customer GetCustomer(int customerId);
}
伺服器會擲回 FaultException 來報告錯誤狀況。
throw new FaultException<CustomerServiceFault>(
new CustomerServiceFault() {
CustomerId = customerId,
ErrorMessage = "Illegal customer Id"
});
每當用戶端向伺服器提出要求時,它可以將錯誤捕捉為一般的例外狀況。
try
{
Customer customer = server.GetCustomer(-1);
}
catch (FaultException<CustomerServiceFault> fault)
{
Console.WriteLine($"Fault received: {fault.Detail.ErrorMessage}");
}
如需錯誤契約的詳細資訊,請參閱 FaultException。
安全性考慮
.NET 遠端處理中的安全性
某些 .NET 遠端通道支援安全性功能,例如通道層的驗證和加密(IPC 和 TCP)。 HTTP 信道依賴 Internet Information Services (IIS)來進行驗證和加密。 儘管有這項支援,但您應該考慮 .NET 遠端處理不安全的通訊協定,並只在完全信任的環境中使用它。 永遠不要向因特網或不受信任的客戶端公開公用遠端端端點。
WCF 中的安全性
WCF 的設計充分考慮到安全性,部分目的是為了解決 .NET Remoting 技術中存在的各類弱點。 WCF 提供傳輸和訊息層級的安全性,並提供許多驗證、授權、加密等選項。 如需詳細資訊,請參閱下列主題:
移轉至 WCF
為什麼要從 Remoting 移轉至 WCF?
.NET 遠端處理是舊版產品。 如 .NET 遠端處理所述,它被視為舊版產品,不建議用於新開發。 建議針對新的和現有的應用程式使用 WCF 或 ASP.NET Web API。
WCF 使用跨平台標準。 WCF 的設計考慮跨平臺互作性,並支援許多業界標準(SOAP、WS-Security、WS-Trust 等)。 WCF 服務可以與在 Windows 以外的作系統上執行的用戶端互通。 遠端功能主要是針對在 Windows作系統上使用 .NET Framework 執行伺服器和用戶端應用程式的環境所設計。
WCF 具有內建安全性。 WCF 的設計考慮安全性,並提供許多驗證、傳輸層級安全性、訊息層級安全性等選項。遠端功能的設計目的是讓應用程式更容易互作,但並非設計為在非信任的環境中安全。 WCF 的設計目的是在受信任和非信任的環境中運作。
移轉建議
以下是從 .NET 遠端移轉至 WCF 的建議步驟:
建立服務合約。 定義您的服務介面類型,並使用 [ServiceContract] 屬性加以標記。標記用戶端可使用 [OperationContract] 呼叫的所有方法。
建立數據合約。 定義將在伺服器和客戶端之間交換的數據類型,並使用 [DataContract] 屬性加以標記。 標記客戶端將允許與 [DataMember] 搭配使用的所有欄位和屬性。
建立錯誤契約(可選)。 建立會在發生錯誤時在伺服器和客戶端之間交換的類型。 使用 [DataContract] 和 [DataMember] 標記這些類型,使其可串行化。 針對您以 [OperationContract] 標記的所有服務作業,也會以 [FaultContract] 標示它們,以指出可能會傳回的錯誤。
設定及部署服務。 建立服務合約之後,下一個步驟是設定系結以在端點公開服務。 如需詳細資訊,請參閱 端點:位址、系結和合約。
將遠端應用程式移轉至 WCF 後,仍然需要移除對 .NET 遠端處理的相依性,這一點非常重要。 這可確保從應用程式移除任何遠端弱點。 這些步驟包括:
停止使用 MarshalByRefObject。 MarshalByRefObject 類型僅適用於遠端處理,WCF 不會使用。 子類別 MarshalByRefObject 的任何應用程式類型都應該移除或變更。
停止使用 [Serializable] 和 ISerializable。 [Serializable] 屬性和 ISerializable 介面原本是設計來串行化信任環境中的類型,而且遠端處理會使用這些類型。 WCF 串行化依賴以 [DataContract] 和 [DataMember] 標記的類型。 應用程式所使用的數據類型應該修改為使用 [DataContract],而不是使用 ISerializable 或 [Serializable]。
移轉案例
現在讓我們看看如何在 WCF 中完成下列常見的遠端處理案例:
伺服器依值將對象傳回給用戶端
伺服器透過參考返回物件給客戶端
用戶端會將物件逐值傳送至伺服器
備註
WCF 中不允許以傳址方式將物件從用戶端傳送至伺服器。
閱讀這些案例時,假設我們適用於 .NET 遠端的基準介面看起來像下列範例。 此處的 .NET 遠程實作並不重要,因為我們只想說明如何使用 WCF 來實作對等功能。
public class RemotingServer : MarshalByRefObject
{
// Demonstrates server returning object by-value
public Customer GetCustomer(int customerId) {…}
// Demonstrates server returning object by-reference
public CustomerReference GetCustomerReference(int customerId) {…}
// Demonstrates client passing object to server by-value
public bool UpdateCustomer(Customer customer) {…}
}
案例 1:服務依值傳回物件
此案例示範以傳值方式將對象傳回給客戶端的伺服器。 WCF 一律會以傳值方式從伺服器傳回物件,因此下列步驟只會描述如何建置一般 WCF 服務。
首先,定義 WCF 服務的公用介面,並以 [ServiceContract] 屬性標記它。 我們使用 [OperationContract] 來識別用戶端將呼叫的伺服器端方法。
[ServiceContract] public interface ICustomerService { [OperationContract] Customer GetCustomer(int customerId); [OperationContract] bool UpdateCustomer(Customer customer); }
下一個步驟是建立此服務的數據合約。 我們藉由建立以 [DataContract] 屬性標示的類別(非介面)來執行此動作。 客戶端和伺服器都可以看到的個別屬性或字段會以 [DataMember] 標示。 如果我們想要允許衍生型別,我們必須使用 [KnownType] 屬性來識別它們。 WCF 唯一允許序列化或反序列化這個服務的類型是服務介面中的類型,以及這些「已知類型」。 嘗試交換未在此清單中的任何其他類型將會遭到拒絕。
[DataContract] [KnownType(typeof(PremiumCustomer))] public class Customer { [DataMember] public string FirstName { get; set; } [DataMember] public string LastName { get; set; } [DataMember] public int CustomerId { get; set; } } [DataContract] public class PremiumCustomer : Customer { [DataMember] public int AccountId { get; set; } }
接下來,我們會提供服務介面的實作。
public class CustomerService : ICustomerService { public Customer GetCustomer(int customerId) { // read from database } public bool UpdateCustomer(Customer customer) { // write to database } }
若要執行 WCF 服務,我們必須宣告使用特定 WCF 系結在特定 URL 公開該服務介面的連接點。 這通常是藉由將下列區段新增至伺服器專案的 web.config 檔案來完成。
<configuration> <system.serviceModel> <services> <service name="Server.CustomerService"> <endpoint address="http://localhost:8083/CustomerService" binding="basicHttpBinding" contract="Shared.ICustomerService" /> </service> </services> </system.serviceModel> </configuration>
然後可以使用下列程式代碼啟動 WCF 服務:
ServiceHost customerServiceHost = new ServiceHost(typeof(CustomerService)); customerServiceHost.Open();
啟動此 ServiceHost 時,它會使用 web.config 檔案來建立適當的合約、系結和端點。 如需組態檔的詳細資訊,請參閱 使用組態檔設定服務。 啟動伺服器的這種方式稱為自我托管。 若要深入瞭解裝載 WCF 服務的其他選擇,請參閱 裝載服務。
用戶端專案的 app.config 必須宣告服務端點的相符系結資訊。 在 Visual Studio 中執行這項作最簡單的方式是使用 [新增服務參考],這會自動更新 app.config 檔案。 或者,您也可以手動新增這些相同的變更。
<configuration> <system.serviceModel> <client> <endpoint name="customerservice" address="http://localhost:8083/CustomerService" binding="basicHttpBinding" contract="Shared.ICustomerService"/> </client> </system.serviceModel> </configuration>
如需使用 新增服務參考的詳細資訊,請參閱 如何:新增、更新或移除服務參考。
現在我們可以從用戶端呼叫 WCF 服務。 我們藉由為該服務建立通道處理站、要求通道,以及直接在該通道上呼叫我們想要的方法來執行此動作。 我們可以這麼做,因為通道會實作服務的介面,併為我們處理基礎要求/回復邏輯。 此方法呼叫的返回值是伺服器回應的反序列化副本。
ChannelFactory<ICustomerService> factory = new ChannelFactory<ICustomerService>("customerservice"); ICustomerService service = factory.CreateChannel(); Customer customer = service.GetCustomer(42); Console.WriteLine($" Customer {customer.FirstName} {customer.LastName} received.");
WCF 從伺服器傳回至客戶端的物件一律依值傳回。 物件是伺服器所傳送的數據的還原副本。 客端戶可以在這些本地副本上呼叫方法,而不必擔心經由回呼涉及伺服器代碼的風險。
案例 2:伺服器依參考傳回物件
此案例示範伺服器以傳址方式提供物件給用戶端。 在 .NET 遠端處理中,任何衍生自 MarshalByRefObject 的類型都會自動以參考方式串行化並處理。 此情境的範例是允許多個用戶端具有獨立具工作階段的伺服器端物件。 如先前所述,WCF 服務傳回的物件一律依值傳回,因此沒有直接對等的傳址物件,但可以使用 EndpointAddress10 物件實現類似於傳址語義的效果。 這是可串行化的依值物件,用戶端可以使用這個物件來取得伺服器上的會話傳址物件。 這可讓多個用戶端擁有具會話功能的伺服器端物件場景。
首先,我們需要定義對應至會話物件本身的 WCF 服務合約。
[ServiceContract(SessionMode = SessionMode.Allowed)] public interface ISessionBoundObject { [OperationContract] string GetCurrentValue(); [OperationContract] void SetCurrentValue(string value); }
小提示
請注意,具狀態的物件會被標記為 [ServiceContract],使其成為標準的 WCF 服務介面。 設定 SessionMode 屬性表示它將是一個支援會話的服務。 在 WCF 中,會話是將兩個端點之間傳送的多個訊息相互關聯的方式。 這表示一旦用戶端取得此服務的連線,客戶端與伺服器之間就會建立會話。 用戶端會針對此單一會話內的所有互動,使用伺服器端物件的單一唯一實例。
接下來,我們需要提供此服務介面的實作。 藉由以 [ServiceBehavior] 表示並設定 InstanceContextMode,我們會告訴 WCF 我們想要針對每個會話使用此類型的唯一實例。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] public class MySessionBoundObject : ISessionBoundObject { private string _value; public string GetCurrentValue() { return _value; } public void SetCurrentValue(string val) { _value = val; } }
現在我們需要一種方法來取得這個具備會話狀態的物件的實例。 我們藉由建立另一個會傳回 EndpointAddress10 物件的 WCF 服務介面來執行此動作。 這是用戶端用來建立會話物件的端點序列化形式。
[ServiceContract] public interface ISessionBoundFactory { [OperationContract] EndpointAddress10 GetInstanceAddress(); }
我們實作此 WCF 服務:
public class SessionBoundFactory : ISessionBoundFactory { public static ChannelFactory<ISessionBoundObject> _factory = new ChannelFactory<ISessionBoundObject>("sessionbound"); public SessionBoundFactory() { } public EndpointAddress10 GetInstanceAddress() { IClientChannel channel = (IClientChannel)_factory.CreateChannel(); return EndpointAddress10.FromEndpointAddress(channel.RemoteAddress); } }
此實作會維護單一通道處理站,以建立會話物件。 呼叫 GetInstanceAddress() 時,它會建立通道,並建立 EndpointAddress10 物件,以有效指向與此通道相關聯的遠端位址。 EndpointAddress10 只是一種可以依值回傳給客戶端的資料類型。
我們需要執行下列兩件事來修改伺服器的組態檔,如下列範例所示:
<宣告一個描述具有會話的物件端點的用戶端區段>。 這是必要的,因為伺服器在此情況中也會做為用戶端。
宣告處理站和會話物件的端點。 這必須允許客戶端與服務端點通訊,以取得 EndpointAddress10 並建立會話通道。
<configuration> <system.serviceModel> <client> <endpoint name="sessionbound" address="net.tcp://localhost:8081/SessionBoundObject" binding="netTcpBinding" contract="Shared.ISessionBoundObject"/> </client> <services> <service name="Server.CustomerService"> <endpoint address="http://localhost:8083/CustomerService" binding="basicHttpBinding" contract="Shared.ICustomerService" /> </service> <service name="Server.MySessionBoundObject"> <endpoint address="net.tcp://localhost:8081/SessionBoundObject" binding="netTcpBinding" contract="Shared.ISessionBoundObject" /> </service> <service name="Server.SessionBoundFactory"> <endpoint address="net.tcp://localhost:8081/SessionBoundFactory" binding="netTcpBinding" contract="Shared.ISessionBoundFactory" /> </service> </services> </system.serviceModel> </configuration>
然後我們可以啟動這些服務:
ServiceHost factoryHost = new ServiceHost(typeof(SessionBoundFactory)); factoryHost.Open(); ServiceHost sessionHost = new ServiceHost(typeof(MySessionBoundObject)); sessionHost.Open();
我們會在其專案的 app.config 檔案中宣告這些相同的端點,藉此設定用戶端。
<configuration> <system.serviceModel> <client> <endpoint name="customerservice" address="http://localhost:8083/CustomerService" binding="basicHttpBinding" contract="Shared.ICustomerService"/> <endpoint name="sessionbound" address="net.tcp://localhost:8081/SessionBoundObject" binding="netTcpBinding" contract="Shared.ISessionBoundObject"/> <endpoint name="factory" address="net.tcp://localhost:8081/SessionBoundFactory" binding="netTcpBinding" contract="Shared.ISessionBoundFactory"/> </client> </system.serviceModel> </configuration>
若要建立及使用此具有工作階段狀態的物件,客戶端必須執行下列步驟:
建立與 ISessionBoundFactory 服務的溝通管道。
使用該通道叫用該服務以取得 EndpointAddress10。
使用 EndpointAddress10 建立通道以取得會話物件。
與會話對象互動,以示範它在多個呼叫之間維持相同的實例。
ChannelFactory<ISessionBoundFactory> channelFactory = new ChannelFactory<ISessionBoundFactory>("factory"); ISessionBoundFactory sessionFactory = channelFactory.CreateChannel(); EndpointAddress10 address1 = sessionFactory.GetInstanceAddress(); EndpointAddress10 address2 = sessionFactory.GetInstanceAddress(); ChannelFactory<ISessionBoundObject> sessionObjectFactory1 = new ChannelFactory<ISessionBoundObject>(new NetTcpBinding(), address1.ToEndpointAddress()); ChannelFactory<ISessionBoundObject> sessionObjectFactory2 = new ChannelFactory<ISessionBoundObject>(new NetTcpBinding(), address2.ToEndpointAddress()); ISessionBoundObject sessionInstance1 = sessionObjectFactory1.CreateChannel(); ISessionBoundObject sessionInstance2 = sessionObjectFactory2.CreateChannel(); sessionInstance1.SetCurrentValue("Hello"); sessionInstance2.SetCurrentValue("World"); if (sessionInstance1.GetCurrentValue() == "Hello" && sessionInstance2.GetCurrentValue() == "World") { Console.WriteLine("sessionful server object works as expected"); }
WCF 一律會依值傳回物件,但可以使用 EndpointAddress10 來支援對等的參考語意。 這可讓用戶端要求會話 WCF 服務實例,之後就可以像任何其他 WCF 服務一樣與其互動。
案例 3:用戶端傳送伺服器 By-Value 實例
客戶端示範如何透過傳值方式將非原始物件實例傳送至伺服器。 由於 WCF 只會依值傳送物件,因此此案例示範一般 WCF 使用方式。
使用與情境 1 相同的 WCF 服務。
使用用戶端建立新的傳值物件 (Customer)、建立通道來與 ICustomerService 服務通訊,並將物件傳送至該物件。
ChannelFactory<ICustomerService> factory = new ChannelFactory<ICustomerService>("customerservice"); ICustomerService service = factory.CreateChannel(); PremiumCustomer customer = new PremiumCustomer { FirstName = "Bob", LastName = "Jones", CustomerId = 43, AccountId = 99}; bool success = service.UpdateCustomer(customer); Console.WriteLine($" Server returned {success}.");
客戶物件將會被序列化,並傳送至伺服器,然後在伺服器中被反序列化成該物件的新副本。
備註
此程式碼也說明傳送「PremiumCustomer」這個衍生類型。 服務介面預期 Customer 物件,但 Customer 類別上的 [KnownType] 屬性也允許 PremiumCustomer 物件。 WCF 會失敗任何透過此服務介面進行的序列化或反序列化其他類型的嘗試。
一般 WCF 資料交換是依值。 這可確保叫用其中一個數據物件的方法只會在本機執行,而不會在其他層叫用程序代碼。 雖然可以達到從 伺服器傳回 的傳址物件之類的專案,但用戶端不可能將傳址對象傳遞 至 伺服器。 在WCF中,可以使用雙工服務來實現需要在用戶端和伺服器之間進行雙向交談的情境。 如需詳細資訊,請參閱 雙工服務。
總結
.NET 遠端處理是一種通訊架構,僅供完全信任的環境使用。 這是舊版產品,僅支援回溯相容性。 它不應該用來建置新的應用程式。 相反地,WCF 的設計考慮安全性,建議用於新的和現有的應用程式。 Microsoft建議將現有的遠端應用程式移轉為改用 WCF 或 ASP.NET Web API。