接下来说ChannelListener和ChannelFactory。
ChannelListener是Service端的技术,用来侦听消息,创建信道栈,并为应用程序提供指向栈顶的引用。
我们不会直接使用ChannelListener,但是我们经常会使用到ServiceHost,殊途同归,其实也是用它来侦听消息。
static void Main(string[] args) { BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.None); Uri address = new Uri("http://localhost/request"); Console.WriteLine("Starting Service..."); IChannelListener<IReplyChannel> listener = binding.BuildChannelListener<IReplyChannel>(address, new BindingParameterCollection()); listener.Open(); IReplyChannel channel = listener.AcceptChannel(); channel.Open(); Console.WriteLine("Service Started~"); Console.WriteLine("Waiting for request..."); RequestContext request = channel.ReceiveRequest(); Message message = request.RequestMessage; string data = message.GetBody<string>(); Message replyMessage = Message.CreateMessage(message.Version, "http://localhost/reply", data); request.Reply(replyMessage); Console.WriteLine("Service stopped!"); message.Close(); request.Close(); channel.Close(); listener.Close(); Console.ReadLine(); }
ChannelFactory是Client端的技术,用来发送消息和定义它所创建的channel的所有者。
我们不会直接使用ChannelFactory,但是我们经常会见到ClientBase<T>,就是在Add Service Reference后自动生成的代码。
static void Main(string[] args) { BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.None); IChannelFactory<IRequestChannel> factory = binding.BuildChannelFactory<IRequestChannel>(new BindingParameterCollection()); factory.Open(); IRequestChannel channel = factory.CreateChannel(new EndpointAddress("http://localhost/request")); channel.Open(); Message requestMessage = Message.CreateMessage(MessageVersion.Soap11, "http://localhost/reply", "This is the body data"); Console.WriteLine("Sending message..."); Message replyMessage = channel.Request(requestMessage); string data = replyMessage.GetBody<string>(); Console.WriteLine("Reply received~"); requestMessage.Close(); replyMessage.Close(); channel.Close(); factory.Close(); Console.ReadLine(); }
上面两段代码共同组成一个request-reply的Demo,代码下载:RequestReply.zip
ChannelListener和ChannelFactory的区别是,前者会关闭全部相关的channel,而后者不会。
ChannelFactory<T>区别于ChannelFactory,前者用于创建多个Client。
最后提到ICommunicationObject,所有的Channel、ChannelListener和ChannelFactory都实现了这个接口,例如:
IOutputChannel : IChannel, ICommunicationObject
这个接口是为了实现状态机。
注意到这个接口的State属性,它是一个enum,对应了状态机的所有state:
public enum CommunicationState { Created = 0, Opening = 1, Opened = 2, Closing = 3, Closed = 4, Faulted = 5, }
ClientBase<T>就是实现了ICommunicationObject接口。
此外,WCF还提供了一个抽象类CommunicationObject,也实现了ICommunicationObject接口,并实现了状态机,所以我们可以使用ICommunicationObject接口暴露的那些event。我们只要从这个抽象类中派生,就可以自定义自己的方法和事件。
WCF本质论P109页的这个例子,是把一个Client转换为ICommunicationObject接口,从而在接口暴露的事件上附加自定义的方法:
至此,Channel全都说完,不过,可惜啊可惜,这些内容只能用来加深我们对WCF的理解,而很少在实际中运用。WCF开发Team需要想想为什么了。