本主题介绍如何在不使用及其关联的对象模型的情况下 System.ServiceModel.ServiceHost 编写 Windows Communication Foundation (WCF) 服务应用程序。
接收消息
若要准备好接收和处理消息,需要执行以下步骤:
创建绑定。
生成通道侦听器。
启动通道侦听器。
读取请求并发送回复。
关闭所有通道对象。
创建绑定
侦听和接收消息的第一步是创建绑定。 WCF 附带了几个内置绑定或系统提供的绑定,用户可以通过实例化它们来直接使用。 此外,还可以通过实例化 CustomBinding 类来创建自己的自定义绑定,该类是列表 1 中的代码的作用。
下面的代码示例创建一个实例 System.ServiceModel.Channels.CustomBinding 并将其添加到 System.ServiceModel.Channels.HttpTransportBindingElement 其 Elements 集合,该集合是用于生成通道堆栈的绑定元素的集合。 在此示例中,由于元素集合只有 HttpTransportBindingElement,因此生成的通道堆栈只有 HTTP 传输通道。
生成 ChannelListener
创建绑定后,我们调用 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