服務 Channel-Level 程序設計
本主題描述如何在不使用 System.ServiceModel.ServiceHost 及其相關聯的物件模型的情況下撰寫 Windows Communication Foundation (WCF) 服務應用程式。
接收訊息
若要準備好接收和處理訊息,需要下列步驟:
建立系結。
建置通道接聽程式。
開啟通道接聽程式。
讀取要求並傳送回復。
關閉所有通道物件。
建立系結
接聽和接收訊息的第一個步驟是建立系結。 WCF 隨附數個內建或系統提供的系結,可藉由具現化其中一個系結來直接使用。 此外,您也可以藉由具現化 CustomBinding 類別來建立自己的自定義系結,也就是清單 1 中的程式碼。
下列程式代碼範例會建立 System.ServiceModel.Channels.CustomBinding 的實例,並將 System.ServiceModel.Channels.HttpTransportBindingElement 加入至其 Elements 集合,這是用來建置通道堆疊的綁定項集合。 在此範例中,由於元素集合中只有 HttpTransportBindingElement,因此產生的通道堆疊只有 HTTP 傳輸通道。
建置通道監聽器
建立繫結之後,我們會呼叫 Binding.BuildChannelListener 來建置通道監聽器,其中類型參數是要建立的通道形狀。 在此範例中,我們使用 System.ServiceModel.Channels.IReplyChannel,因為我們想要在要求/回復訊息交換模式中接聽傳入訊息。
IReplyChannel 用於接收要求訊息和傳回回復訊息。 呼叫 IReplyChannel.ReceiveRequest 會傳回 System.ServiceModel.Channels.IRequestChannel,可用來接收要求訊息,以及傳回回復訊息。
建立接聽程式時,我們會傳遞其接聽的網路位址,在此案例中 http://localhost:8080/channelapp
。 一般而言,每個傳輸通道都支援一或多個位址配置,例如,HTTP 傳輸同時支援 HTTP 和 HTTPs 配置。
我們也會在建立接聽程式時傳遞空 System.ServiceModel.Channels.BindingParameterCollection。 係結參數是傳遞參數的機制,可控制接聽程式的建置方式。 在我們的範例中,我們不會使用任何這類參數,因此我們會傳遞空集合。
監聽傳入訊息
接著,我們會在接聽程式上呼叫 ICommunicationObject.Open,並開始接受通道。 IChannelListener<TChannel>.AcceptChannel 的行為取決於傳輸是連線導向還是無連線。 針對連線導向傳輸,AcceptChannel 會封鎖直到新的連線要求傳入為止,此時它會傳回代表該新連線的新通道。 對於無狀態連線的傳輸,例如 HTTP,AcceptChannel 會立即傳回傳輸接聽程式所建立的唯一通道。
在此範例中,接聽程式會傳回實作 IReplyChannel的通道。 為了在此通道上接收訊息,我們先呼叫 ICommunicationObject.Open,使其處於準備好進行通訊的狀態。 然後,我們會呼叫 ReceiveRequest 封鎖訊息,直到訊息送達為止。
讀取要求並傳送回復
當 ReceiveRequest 傳回 RequestContext時,我們會使用其 RequestMessage 屬性取得收到的訊息。 我們會寫出訊息的動作和本文內容(我們假設是字串)。
為了傳送回復,我們會在此案例中建立新的回復訊息,以傳回我們在要求中收到的字串數據。 然後,我們會呼叫 Reply 來傳送回復訊息。
關閉物件
為了避免資源流失,當不再需要物件時,關閉通訊中使用的物件非常重要。 在此範例中,我們會關閉要求訊息、要求內容、通道和接聽程式。
下列程式代碼範例顯示通道接聽程式只接收一則訊息的基本服務。 真正的服務會不斷接受通道並接收訊息,直到服務結束。
using System;
using System.ServiceModel.Channels;
namespace ProgrammingChannels
{
class Service
{
static void RunService()
{
//Step1: Create a custom binding with just TCP.
BindingElement[] bindingElements = new BindingElement[2];
bindingElements[0] = new TextMessageEncodingBindingElement();
bindingElements[1] = new HttpTransportBindingElement();
CustomBinding binding = new CustomBinding(bindingElements);
//Step2: Use the binding to build the channel listener.
IChannelListener<IReplyChannel> listener =
binding.BuildChannelListener<IReplyChannel>(
new Uri("http://localhost:8080/channelapp"),
new BindingParameterCollection());
//Step3: Listening for messages.
listener.Open();
Console.WriteLine(
"Listening for incoming channel connections");
//Wait for and accept incoming connections.
IReplyChannel channel = listener.AcceptChannel();
Console.WriteLine("Channel accepted. Listening for messages");
//Open the accepted channel.
channel.Open();
//Wait for and receive a message from the channel.
RequestContext request= channel.ReceiveRequest();
//Step4: Reading the request message.
Message message = request.RequestMessage;
Console.WriteLine("Message received");
Console.WriteLine($"Message action: {message.Headers.Action}");
string data=message.GetBody<string>();
Console.WriteLine($"Message content: {data}");
//Send a reply.
Message replymessage=Message.CreateMessage(
binding.MessageVersion,
"http://contoso.com/someotheraction",
data);
request.Reply(replymessage);
//Step5: Closing objects.
//Do not forget to close the message.
message.Close();
//Do not forget to close RequestContext.
request.Close();
//Do not forget to close channels.
channel.Close();
//Do not forget to close listeners.
listener.Close();
}
public static void Main()
{
Service.RunService();
Console.WriteLine("Press enter to exit");
Console.ReadLine();
}
}
}
Imports System.ServiceModel.Channels
Namespace ProgrammingChannels
Friend Class Service
Private Shared Sub RunService()
'Step1: Create a custom binding with just TCP.
Dim bindingElements(1) As BindingElement = {New TextMessageEncodingBindingElement(), _
New HttpTransportBindingElement()}
Dim binding As New CustomBinding(bindingElements)
'Step2: Use the binding to build the channel listener.
Dim listener = binding.BuildChannelListener(Of IReplyChannel)(New Uri("http://localhost:8080/channelapp"), _
New BindingParameterCollection())
'Step3: Listening for messages.
listener.Open()
Console.WriteLine("Listening for incoming channel connections")
'Wait for and accept incoming connections.
Dim channel = listener.AcceptChannel()
Console.WriteLine("Channel accepted. Listening for messages")
'Open the accepted channel.
channel.Open()
'Wait for and receive a message from the channel.
Dim request = channel.ReceiveRequest()
'Step4: Reading the request message.
Dim message = request.RequestMessage
Console.WriteLine("Message received")
Console.WriteLine("Message action: {0}", message.Headers.Action)
Dim data = message.GetBody(Of String)()
Console.WriteLine("Message content: {0}", data)
'Send a reply.
Dim replymessage = Message.CreateMessage(binding.MessageVersion, _
"http://contoso.com/someotheraction", data)
request.Reply(replymessage)
'Step5: Closing objects.
'Do not forget to close the message.
message.Close()
'Do not forget to close RequestContext.
request.Close()
'Do not forget to close channels.
channel.Close()
'Do not forget to close listeners.
listener.Close()
End Sub
Public Shared Sub Main()
Service.RunService()
Console.WriteLine("Press enter to exit")
Console.ReadLine()
End Sub
End Class
End Namespace