WCF - 绑定后续之自定义绑定
自定义信道基类
WCF是一个极具扩展性的通信框架 无论在服务模型层还是信道层 都具有很多扩展点 而信道层的扩展点主要体现在实现自定义信道以增强信道栈处理信息的能力 比如我们可以扩展信道层 实现一个自定义的信道 该信道提供一些方法将信息压缩 使信息的传输更快速 下面创建一个自定义的信道基类 实现当信道的某些方法执行时打印出该信道类型的名字和它方法的名字 接着调用下一个信道的方法 要实现自定义信道基类 可以使自定义信道基类派生于ChannelBase 因为ChannelBase是所有信道的基类 它通过实现各种接口IChannel、ICommunicationObject、IDefaultCommunicationTimeouts和继承CommunicationObjec类进而拥有信道最基本的操作方法
using System.ServiceModel.Channels; namespace Custom
{
public abstract class SimpleChannelBase : ChannelBase
{
protected void Print(string methodName)
{
Console.WriteLine("{0}.{1}", this.GetType().Name, methodName);
}
public ChannelBase InnerChannel { get; private set; }
public SimpleChannelBase(ChannelManagerBase channelManager, ChannelBase innerChannel)
: base(channelManager)
{
this.InnerChannel = innerChannel;
} protected override void OnAbort()
{
this.Print("OnAbort()");
this.InnerChannel.Abort();
} protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
{
this.Print("OnBeginClose()");
return this.InnerChannel.BeginClose(timeout, callback, state);
} protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
{
this.Print("OnBeginOpen()");
return this.InnerChannel.BeginOpen(timeout, callback, state);
} protected override void OnClose(TimeSpan timeout)
{
this.Print("OnClose()");
this.InnerChannel.Close(timeout);
} protected override void OnEndClose(IAsyncResult result)
{
this.Print("OnEndClose()");
this.InnerChannel.EndClose(result);
} protected override void OnEndOpen(IAsyncResult result)
{
this.Print("OnEndOpen()");
this.InnerChannel.EndOpen(result);
} protected override void OnOpen(TimeSpan timeout)
{
this.Print("OnOpen()");
this.InnerChannel.Open(timeout);
} public override T GetProperty<T>()
{
return this.InnerChannel.GetProperty<T>();
}
}
}
自定义请求-回复模式的请求信道
通过继承SimpleChannelBase创建自定义的、在客户端用于发送请求和接收服务端回复的请求信道SimpleRequestChannel 该类不但要继承SimpleChannelBase还需要实现IRequestChannel以模仿请求信道的功能
using System.ServiceModel.Channels;
using System.ServiceModel; namespace Custom
{
public class SimpleRequestChannel : SimpleChannelBase, IRequestChannel
{
public IRequestChannel InnerRequestChannel
{
get { return (IRequestChannel)this.InnerChannel; }
} public SimpleRequestChannel(ChannelManagerBase channelManager, IRequestChannel innerChannel)
: base(channelManager, (ChannelBase)innerChannel)
{
this.Print("SimpleRequestChannel()");
} public IAsyncResult BeginRequest(Message message, TimeSpan timeout, AsyncCallback callback, object state)
{
this.Print("BeginRequest()");
return this.InnerRequestChannel.BeginRequest(message, timeout, callback, state);
} public IAsyncResult BeginRequest(Message message, AsyncCallback callback, object state)
{
this.Print("BeginRequest()");
return this.InnerRequestChannel.BeginRequest(message, callback, state);
} public Message EndRequest(IAsyncResult result)
{
this.Print("EndRequest()");
return this.InnerRequestChannel.EndRequest(result);
} public EndpointAddress RemoteAddress
{
get { return this.InnerRequestChannel.RemoteAddress; }
} public Message Request(Message message, TimeSpan timeout)
{
this.Print("Request");
return this.InnerRequestChannel.Request(message, timeout);
} public Message Request(Message message)
{
this.Print("Request");
return this.InnerRequestChannel.Request(message);
} public Uri Via
{
get { return this.InnerRequestChannel.Via; }
}
}
}
自定义请求-回复模式的回复信道
using System.ServiceModel.Channels;
using System.ServiceModel; namespace Custom
{
public class SimpleReplyChannel : SimpleChannelBase, IReplyChannel
{
public IReplyChannel InnerReplyChannel
{
get { return (IReplyChannel)this.InnerChannel; }
} public SimpleReplyChannel(ChannelManagerBase channelManager, IReplyChannel innerChannel)
: base(channelManager, (ChannelBase)innerChannel)
{
this.Print("SimpleReplyChannel()");
} public IAsyncResult BeginReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state)
{
this.Print("BeginReceiveRequest()");
return this.InnerReplyChannel.BeginReceiveRequest(timeout, callback, state);
} public IAsyncResult BeginReceiveRequest(AsyncCallback callback, object state)
{
this.Print("BeginReceiveRequest()");
return this.InnerReplyChannel.BeginReceiveRequest(callback, state);
} public IAsyncResult BeginTryReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state)
{
this.Print("BeginTryReceiveRequest()");
return this.InnerReplyChannel.BeginTryReceiveRequest(timeout, callback, state);
} public IAsyncResult BeginWaitForRequest(TimeSpan timeout, AsyncCallback callback, object state)
{
this.Print("BeginWaitForRequest()");
return this.InnerReplyChannel.BeginWaitForRequest(timeout, callback, state);
} public RequestContext EndReceiveRequest(IAsyncResult result)
{
this.Print("EndReceiveRequest()");
return this.InnerReplyChannel.EndReceiveRequest(result);
} public bool EndTryReceiveRequest(IAsyncResult result, out RequestContext context)
{
this.Print("EndTryReceiveRequest()");
return this.InnerReplyChannel.EndTryReceiveRequest(result, out context);
} public bool EndWaitForRequest(IAsyncResult result)
{
this.Print("EndWaitForRequest()");
return this.InnerReplyChannel.EndWaitForRequest(result);
} public EndpointAddress LocalAddress
{
get{ return this.InnerReplyChannel.LocalAddress;}
} public RequestContext ReceiveRequest(TimeSpan timeout)
{
this.Print("ReceiveRequest()");
return this.InnerReplyChannel.ReceiveRequest(timeout);
} public RequestContext ReceiveRequest()
{
this.Print("ReceiveRequest()");
return this.InnerReplyChannel.ReceiveRequest();
} public bool TryReceiveRequest(TimeSpan timeout, out RequestContext context)
{
this.Print("TryReceiveRequest()");
return this.InnerReplyChannel.TryReceiveRequest(timeout, out context);
} public bool WaitForRequest(TimeSpan timeout)
{
this.Print("WaitForRequest()");
return this.InnerReplyChannel.WaitForRequest(timeout);
}
}
}
自定义双工会话信道
using System.ServiceModel.Channels;
using System.ServiceModel; namespace Custom
{
public class SimpleDuplexSessionChannel : SimpleChannelBase, IDuplexSessionChannel
{
public IDuplexSessionChannel InnerDuplexSessionChannel
{
get { return (IDuplexSessionChannel)this.InnerChannel; }
} public SimpleDuplexSessionChannel(ChannelManagerBase channelManager, IDuplexSessionChannel innerChannel)
: base(channelManager, (ChannelBase)innerChannel)
{
this.Print("SimpleDuplexSessionChannel()");
} public IAsyncResult BeginReceive(TimeSpan timeout, AsyncCallback callback, object state)
{
this.Print("BeginReceive()");
return this.InnerDuplexSessionChannel.BeginReceive(timeout, callback, state);
} public IAsyncResult BeginReceive(AsyncCallback callback, object state)
{
this.Print("BeginReceive()");
return this.InnerDuplexSessionChannel.BeginReceive(callback, state);
} public IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state)
{
this.Print("BeginTryReceive()");
return this.InnerDuplexSessionChannel.BeginTryReceive(timeout, callback, state);
} public IAsyncResult BeginWaitForMessage(TimeSpan timeout, AsyncCallback callback, object state)
{
this.Print("BeginWaitForMessage()");
return this.InnerDuplexSessionChannel.BeginWaitForMessage(timeout, callback, state);
} public Message EndReceive(IAsyncResult result)
{
this.Print("EndReceive()");
return this.InnerDuplexSessionChannel.EndReceive(result);
} public bool EndTryReceive(IAsyncResult result, out Message message)
{
this.Print("EndTryReceive()");
return this.InnerDuplexSessionChannel.EndTryReceive(result, out message);
} public bool EndWaitForMessage(IAsyncResult result)
{
this.Print("EndWaitForMessage()");
return this.InnerDuplexSessionChannel.EndWaitForMessage(result);
} public EndpointAddress LocalAddress
{
get { return this.InnerDuplexSessionChannel.LocalAddress; }
} public Message Receive(TimeSpan timeout)
{
this.Print("Receive()");
return this.InnerDuplexSessionChannel.Receive(timeout);
} public Message Receive()
{
this.Print("Receive()");
return this.InnerDuplexSessionChannel.Receive();
} public bool TryReceive(TimeSpan timeout, out Message message)
{
this.Print("TryReceive()");
return this.InnerDuplexSessionChannel.TryReceive(timeout, out message);
} public bool WaitForMessage(TimeSpan timeout)
{
this.Print("WaitForMessage()");
return this.InnerDuplexSessionChannel.WaitForMessage(timeout);
} public IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state)
{
this.Print("BeginSend()");
return this.InnerDuplexSessionChannel.BeginSend(message, timeout, callback, state);
} public IAsyncResult BeginSend(Message message, AsyncCallback callback, object state)
{
this.Print("BeginSend()");
return this.InnerDuplexSessionChannel.BeginSend(message, callback, state);
} public void EndSend(IAsyncResult result)
{
this.Print("EndSend()");
this.InnerDuplexSessionChannel.EndSend(result);
} public EndpointAddress RemoteAddress
{
get { return this.InnerDuplexSessionChannel.RemoteAddress; }
} public void Send(Message message, TimeSpan timeout)
{
this.Print("Send()");
this.InnerDuplexSessionChannel.Send(message, timeout);
} public void Send(Message message)
{
this.Print("Send()");
this.InnerDuplexSessionChannel.Send(message);
} public Uri Via
{
get { return this.InnerDuplexSessionChannel.Via; }
} public IDuplexSession Session
{
get { return this.InnerDuplexSessionChannel.Session; }
}
}
}
自定义信道侦听器基类
我们要创建自定义的信道侦听器 则需要继承ChannelListenerBase<TChannel>抽象基类 因为该基类实现了IChannelListener<TChannel>接口 即所有关于侦听器的方法和属性的内部实现都ChannelListenerBase<TChannel>中完成了 我们要定义一个新版的侦听器基类 以便添加新的操作方法 则唯一途径就是派生于ChannelListenerBase<TChannel>类
using System.ServiceModel.Channels; namespace Custom
{
public abstract class SimpleChannelListenerBase<TChannel> : ChannelListenerBase<TChannel> where TChannel : class, IChannel
{
protected void Print(string methodName)
{
Console.WriteLine("{0}.{1}", this.GetType().Name, methodName);
}
public IChannelListener<TChannel> InnerChannelListener { get; private set; }
public SimpleChannelListenerBase(BindingContext context)
{
this.InnerChannelListener = context.BuildInnerChannelListener<TChannel>();
}
protected override IAsyncResult OnBeginAcceptChannel(TimeSpan timeout, AsyncCallback callback, object state)
{
this.Print("OnBeginAcceptChannel()");
return this.InnerChannelListener.BeginAcceptChannel(timeout, callback, state);
}
protected override IAsyncResult OnBeginWaitForChannel(TimeSpan timeout, AsyncCallback callback, object state)
{
this.Print("OnBeginWaitForChannel()");
return this.InnerChannelListener.BeginWaitForChannel(timeout, callback, state);
}
protected override bool OnEndWaitForChannel(IAsyncResult result)
{
this.Print("OnEndWaitForChannel()");
return this.InnerChannelListener.EndWaitForChannel(result);
}
protected override bool OnWaitForChannel(TimeSpan timeout)
{
this.Print("OnWaitForChannel()");
return this.InnerChannelListener.WaitForChannel(timeout);
}
public override Uri Uri
{
get{return this.InnerChannelListener.Uri;}
}
protected override void OnAbort()
{
this.Print("OnAbort()");
this.InnerChannelListener.Abort();
}
protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
{
this.Print("OnBeginClose()");
return this.InnerChannelListener.BeginClose(timeout, callback, state);
}
protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
{
this.Print("OnBeginOpen()");
return this.InnerChannelListener.BeginOpen(timeout, callback, state);
}
protected override void OnClose(TimeSpan timeout)
{
this.Print("OnClose()");
this.InnerChannelListener.Close(timeout);
}
protected override void OnEndClose(IAsyncResult result)
{
this.Print("OnEndClose()");
this.InnerChannelListener.EndClose(result);
}
protected override void OnEndOpen(IAsyncResult result)
{
this.Print("OnEndOpen()");
this.InnerChannelListener.EndOpen(result);
}
protected override void OnOpen(TimeSpan timeout)
{
this.Print("OnOpen()");
this.InnerChannelListener.Open(timeout);
}
public override T GetProperty<T>()
{
return this.InnerChannelListener.GetProperty<T>();
}
}
}
自定义基于普通信道的信道侦听器
using System.ServiceModel.Channels; namespace Custom
{
public class SimpleDatagramChannelListener<TChannel> : SimpleChannelListenerBase<TChannel> where TChannel : class,IChannel
{
public SimpleDatagramChannelListener(BindingContext context)
: base(context)
{
this.Print("SimpleDatagramChannelListener()");
}
protected override TChannel OnAcceptChannel(TimeSpan timeout)
{
this.Print("OnAcceptChannel()");
IReplyChannel innerChannel = (IReplyChannel)this.InnerChannelListener.AcceptChannel(timeout);
if (null != innerChannel)
{
return new SimpleReplyChannel(this, innerChannel) as TChannel;
}
return null;
}
protected override TChannel OnEndAcceptChannel(IAsyncResult result)
{
this.Print("OnEndAcceptChannel()");
IReplyChannel innerChannel = (IReplyChannel)this.InnerChannelListener.EndAcceptChannel(result);
if (null != innerChannel)
{
return new SimpleReplyChannel(this, innerChannel) as TChannel;
}
return null;
}
}
}
自定义基于会话信道的信道侦听器
using System.ServiceModel.Channels; namespace Custom
{
public class SimpleSessionChannelListener<TChannel> : SimpleChannelListenerBase<TChannel> where TChannel : class, IChannel
{
public SimpleSessionChannelListener(BindingContext context)
: base(context)
{
this.Print("SimpleSessionChannelListener()");
}
protected override TChannel OnAcceptChannel(TimeSpan timeout)
{
this.Print("OnAcceptChannel()");
IDuplexSessionChannel innerChannel = (IDuplexSessionChannel)this.InnerChannelListener.AcceptChannel(timeout);
return new SimpleDuplexSessionChannel(this, innerChannel) as TChannel;
}
protected override TChannel OnEndAcceptChannel(IAsyncResult result)
{
this.Print("OnEndAcceptChannel()");
IDuplexSessionChannel innerChannel = (IDuplexSessionChannel)this.InnerChannelListener.EndAcceptChannel(result);
if (null != innerChannel)
{
return new SimpleDuplexSessionChannel(this, innerChannel) as TChannel;
}
return default(TChannel);
}
}
}
自定义信道工厂基类
using System.ServiceModel.Channels;
using System.ServiceModel; namespace Custom
{
public abstract class SimpleChannelFactoryBase<TChannel> : ChannelFactoryBase<TChannel>
{
protected void Print(string methodName)
{
Console.WriteLine("{0}.{1}", this.GetType().Name, methodName);
}
public IChannelFactory<TChannel> InnerChannelFactory { get; private set; }
public SimpleChannelFactoryBase(BindingContext context)
{
this.InnerChannelFactory = context.BuildInnerChannelFactory<TChannel>();
}
protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
{
this.Print("OnBeginOpen()");
return this.InnerChannelFactory.BeginOpen(timeout, callback, state);
} protected override void OnEndOpen(IAsyncResult result)
{
this.Print("OnEndOpen()");
this.InnerChannelFactory.EndOpen(result);
} protected override void OnOpen(TimeSpan timeout)
{
this.Print("OnOpen()");
this.InnerChannelFactory.Open(timeout);
} public override T GetProperty<T>()
{
return this.InnerChannelFactory.GetProperty<T>();
}
}
}
自定义基于普通信道的信道工厂
using System.ServiceModel.Channels;
using System.ServiceModel; namespace Custom
{
public class SimpleDatagramChannelFactory<TChannel> : SimpleChannelFactoryBase<TChannel>
{
public SimpleDatagramChannelFactory(BindingContext context) :
base(context)
{
this.Print("SimpleDatagramChannelFactory()");
} protected override TChannel OnCreateChannel(EndpointAddress address, Uri via)
{
this.Print("OnCreateChannel()");
IRequestChannel innerChannel = (IRequestChannel)this.InnerChannelFactory.CreateChannel(address, via);
if (null != innerChannel)
{
return (TChannel)(object)new SimpleRequestChannel(this, innerChannel);
}
else
{
return default(TChannel);
}
}
}
}
自定义基于会话信道的信道工厂
using System.ServiceModel.Channels;
using System.ServiceModel; namespace Custom
{
public class SimpleSessionChannelFactory<TChannel> : SimpleChannelFactoryBase<TChannel>
{
public SimpleSessionChannelFactory(BindingContext context)
: base(context)
{
this.Print("SimpleSessionChannelFactory()");
}
protected override TChannel OnCreateChannel(EndpointAddress address, Uri via)
{
this.Print("OnCreateChannel()");
IDuplexSessionChannel innerChannel = (IDuplexSessionChannel)this.InnerChannelFactory.CreateChannel(address, via);
if (null != innerChannel)
{
return (TChannel)(object)new SimpleDuplexSessionChannel(this, innerChannel);
}
return default(TChannel);
}
}
}
自定义基于普通信道的绑定元素
using System.ServiceModel.Channels; namespace Custom
{
public class SimpleDatagramBindingElement:BindingElement
{
protected void Print(string methodName)
{
Console.WriteLine("{0}.{1}", this.GetType().Name, methodName);
}
public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
{
this.Print("BuildChannelListener<TChannel>()");
return new SimpleDatagramChannelListener<TChannel>(context);
}
public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
{
this.Print("BuildChannelFactory<TChannel>()");
return new SimpleDatagramChannelFactory<TChannel>(context);
} public override BindingElement Clone()
{
return new SimpleDatagramBindingElement();
}
public override T GetProperty<T>(BindingContext context)
{
return context.GetInnerProperty<T>();
}
}
}
自定义基于会话信道的绑定元素
using System.ServiceModel.Channels; namespace Custom
{
public class SimpleSessionBindingElement: BindingElement
{
protected void Print(string methodName)
{
Console.WriteLine("{0}.{1}", this.GetType().Name, methodName);
}
public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
{
this.Print("BuildChannelListener<TChannel>()");
return new SimpleSessionChannelListener<TChannel>(context);
}
public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
{
this.Print("BuildChannelFactory<TChannel>()");
return new SimpleSessionChannelFactory<TChannel>(context);
}
public override BindingElement Clone()
{
return new SimpleSessionBindingElement();
}
public override T GetProperty<T>(BindingContext context)
{
return context.GetInnerProperty<T>();
}
}
}
自定义基于普通信道的绑定对象
在前面的示例中 我们创建了自定义的信道、信道侦听器和信道工厂、绑定元素 所有这些对象都必须通过一个具体的绑定对象才能将它们全部应用到WCF运行环境中
using System.ServiceModel.Channels; namespace Custom
{
public class SimpleDatagramBinding : Binding
{
protected void Print(string methodName)
{
Console.WriteLine("{0}.{1}", this.GetType().Name, methodName);
}
private TransportBindingElement transportBindingElement;
private BindingElementCollection bindingElementCollection;
public SimpleDatagramBinding()
{
BindingElement[] bindingElements = new BindingElement[]
{
new SimpleDatagramBindingElement(),
new TextMessageEncodingBindingElement(),
new HttpTransportBindingElement()
};
bindingElementCollection = new BindingElementCollection(bindingElements);
transportBindingElement = (TransportBindingElement)bindingElements[];
}
public override BindingElementCollection CreateBindingElements()
{
return bindingElementCollection;
}
public override string Scheme
{
get { return transportBindingElement.Scheme; }
}
}
}
自定义基于会话信道的绑定对象
using System.ServiceModel.Channels; namespace Custom
{
public class SimpleSessionBinding : Binding
{
private TransportBindingElement transportBindingElement;
private BindingElementCollection bindingElementCollection;
public SimpleSessionBinding()
{
BindingElement[] bindingElements = new BindingElement[]
{
new SimpleSessionBindingElement(),
new BinaryMessageEncodingBindingElement(),
new TcpTransportBindingElement()
};
bindingElementCollection = new BindingElementCollection(bindingElements);
transportBindingElement = (TransportBindingElement)bindingElements[];
}
public override BindingElementCollection CreateBindingElements()
{
return bindingElementCollection;
}
public override string Scheme
{
get { return transportBindingElement.Scheme; }
}
}
}
测试自定义绑定对象
我们使用这个自定义绑定对象来做测试 修改计算服务的例子 打开Service项目的CalculatorService文件 修改如下
using Service.Interface; namespace Service
{
public class CalculatorService:ICalculator
{
public double Add(double x, double y)
{
var result = x + y;
Console.WriteLine("完成接收请求和回复…………");
return result;
}
}
}
打开Hosting项目的入口文件 修改如下
using System.ServiceModel;
using Service.Interface;
using Service;
using Custom; namespace Hosting
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(CalculatorService));
host.AddServiceEndpoint(typeof(ICalculator), new SimpleDatagramBinding(), "http://127.0.0.1:7777/calculatorservice");
host.Open();
Console.WriteLine("服务已开启……");
Console.Read();
}
}
}
用管理员身份运行该程序 则会输出以下信息
SimpleDatagramBindingElement.BuildChannelListener<TChannel>()
SimpleDatagramChannelListener`1.SimpleDatagramChannelListener()
SimpleDatagramChannelListener`1.OnOpen()
服务已开启……
SimpleDatagramChannelListener`1.OnBeginAcceptChannel()
SimpleDatagramChannelListener`1.OnEndAcceptChannel()
SimpleReplyChannel.SimpleReplyChannel()
SimpleDatagramChannelListener`1.OnBeginAcceptChannel()
SimpleReplyChannel.OnOpen()
SimpleReplyChannel.BeginTryReceiveRequest()
绑定对象创建信道侦听器的流程
WsHttpBinding是一个内置的绑定对象 WsHttpBinding被实例化时 它会调用自身的BuildChannelListener<TChannel>()方法创建信道侦听器管道 因为它有
两个内置的绑定元素HttpTransportBindingElement(传输元素)和TextMessageEncodingBindingElement(编码元素)两个绑定元素会自动创建自身的
信道侦听器 前一个侦听器侦听到请求就会传输信息到客户端 后一个侦听器侦听到请求则会处理请求中的信息编码
接着我们来看上面的例子 通过实例化自定义的绑定元素后 程序如何执行的 首先new SimpleDatagramBinding()执行时 将创建自定义绑定对象 - 绑定对象自动调用自身的BuildChannelListener<TChannel>()方法创建信道侦听器管道 我们可以把这个管道理解为一个大的侦听器容器(信道栈) 它承载的是绑定对象中的每个绑定元素自动创建的对应的侦听器 多个侦听器存储在这个信道侦听器通道中 该通道被打开以便侦听请求的信息 请求信息一旦抵达 通道则将依次调用每个绑定元素对应的信道的方法
SimpleDatagramBindingElement.BuildChannelListener<TChannel>() //自定义绑定元素调用该方法创建了一个自定义的信道侦听器
SimpleDatagramChannelListener`.SimpleDatagramChannelListener() //自定义的信道侦听器被实例化
SimpleDatagramChannelListener`.OnOpen() //自定义的信道侦听器创建完成后自动打开以便侦听请求
服务已开启……
SimpleDatagramChannelListener`.OnBeginAcceptChannel() //信道侦听器在开始创建信道时将触发这个事件
SimpleDatagramChannelListener`.OnEndAcceptChannel() //信道侦听器在创建完信道时将触发这个事件
SimpleReplyChannel.SimpleReplyChannel() //信道侦听器创建了一个回复信道
SimpleDatagramChannelListener`.OnBeginAcceptChannel() //信道被创建 则该事件被触发
SimpleReplyChannel.OnOpen() //打开回复信道 以便回复信息
SimpleReplyChannel.BeginTryReceiveRequest() //开始一个用于接收请求的异步操作
在我们自定义的绑定对象中 除了自定义的绑定元素 还有两个绑定元素被添加到绑定对象中 如下代码片段所示:
public SimpleDatagramBinding()
{
BindingElement[] bindingElements = new BindingElement[]
{
new SimpleDatagramBindingElement(), //自定义的绑定元素
new TextMessageEncodingBindingElement(), //编码绑定元素
new HttpTransportBindingElement() //传输绑定元素
};
bindingElementCollection = new BindingElementCollection(bindingElements);
transportBindingElement = (TransportBindingElement)bindingElements[];
}
一个是用于传输的绑定元素HttpTransportBindingElemen和用于编码的绑定元素SimpleDatagramBindingElement 两个绑定元素也都会调用自身的BuildChannelListener<TChannel>()方法创建各自的信道侦听器(隐式的创建了信道侦听器同时传输绑定元素还隐式创建了传输信道 而编码绑定元素隐式创建了编码信道) 这些信道再加上上面的自定义绑定元素创建的信道侦听器 就组成了一个信道栈(即信道通道)
接着我们打开Client项目的入口文件 修改如下:
using System.ServiceModel;
using Service.Interface;
using Custom; namespace Client
{
class Program
{
static void Main(string[] args)
{
EndpointAddress pointAddress=new EndpointAddress("http://127.0.0.1:7777/calculatorservice");
ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>(new SimpleDatagramBinding(), pointAddress);
//第一个信道工厂创建的服务代理
ICalculator proxy = channelFactory.CreateChannel();
//发送第一个请求
proxy.Add(, );
Console.WriteLine("完成请求并接收到回复……");
//发送第二个请求
proxy.Add(, );
Console.WriteLine("完成请求并接收到回复……");
(proxy as ICommunicationObject).Close(); //第二个信道工厂创建的服务代理
proxy = channelFactory.CreateChannel();
//发送第一个请求
proxy.Add(, );
Console.WriteLine("完成请求并接收到回复……");
//发送第二个请求
proxy.Add(, );
Console.WriteLine("完成请求并接收到回复……");
(proxy as ICommunicationObject).Close();
}
}
}
保持Hosting的运行 在运行Client 输出如下
new SimpleDatagramBinding()被实例化 - 它调用自身的BuildChannelFactory<TChannel>()方法创建信道工厂管道 因为它有两个内置的绑定元素TextMessageEncodingBindingElement(编码元素)和HttpTransportBindingElement(传输元素)两个绑定元素会自动创建自身的信道工厂 前一个信道工厂通过编码信道将信息编码接着使用后一个信道工厂通过传输信道发送信息请求到服务端
SimpleDatagramBindingElement.BuildChannelFactory<TChannel>() //自定义的绑定元素调用该方法创建了一个信道工厂
SimpleDatagramChannelFactory`.SimpleDatagramChannelFactory() //自定义的信道工厂被初始化
SimpleDatagramChannelFactory`.OnOpen() //自定义的信道工厂在开启时将触发这个事件
SimpleDatagramChannelFactory`.OnCreateChannel() //自定义的信道工厂在开始创建请求信道时将触发这个事件
SimpleRequestChannel.SimpleRequestChannel() //自定义的信道工厂创建了一个自定义的请求信道
SimpleRequestChannel.OnOpen() //自定义的请求信道自动开启
SimpleRequestChannel.Request //自定义的请求信道发送发送第一个请求并接收服务端的回复信息
完成请求并接收到回复……
SimpleRequestChannel.Request //自定义的请求信道发送发送第二个请求并接收服务端的回复信息
完成请求并接收到回复……
SimpleRequestChannel.OnClose() //第一个服务代理被关闭 此时信道工厂管道并没关闭 它所有的信道还存在 请参看代码 关闭的是代理对象
SimpleDatagramChannelFactory`.OnCreateChannel() //自定义的信道工厂在开始创建请求信道时将触发这个事件
SimpleRequestChannel.SimpleRequestChannel() //重复以上步骤
SimpleRequestChannel.OnOpen() //重复以上步骤
SimpleRequestChannel.Request //重复以上步骤
完成请求并接收到回复……
SimpleRequestChannel.Request
完成请求并接收到回复……
SimpleRequestChannel.OnClose() //重复以上步骤
而此时在服务端因为侦听到了请求 所以会如下输出信息
SimpleDatagramBindingElement.BuildChannelListener<TChannel>() //自定义绑定元素调用该方法创建了一个自定义的信道侦听器
SimpleDatagramChannelListener`.SimpleDatagramChannelListener() //自定义的信道侦听器被实例化
SimpleDatagramChannelListener`.OnOpen() //自定义的信道侦听器创建完成后自动打开以便侦听请求
服务已开启……
SimpleDatagramChannelListener`.OnBeginAcceptChannel() SimpleDatagramChannelListener`.OnEndAcceptChannel()
SimpleReplyChannel.SimpleReplyChannel() //信道侦听器创建了一个回复信道
SimpleDatagramChannelListener`.OnBeginAcceptChannel()
SimpleReplyChannel.OnOpen() //打开回复信道 以便回复信息
SimpleReplyChannel.BeginTryReceiveRequest() //开始一个用于接收请求的异步操作
SimpleReplyChannel.EndTryReceiveRequest() //完成一个用于接收请求的异步操作
SimpleReplyChannel.BeginTryReceiveRequest() //开始一个用于接收请求的异步操作 此时第一个请求抵达
完成接收请求和回复……
SimpleReplyChannel.EndTryReceiveRequest() //完成一个用于接收请求的异步操作
SimpleReplyChannel.BeginTryReceiveRequest() //开始一个用于接收请求的异步操作 此时第二个请求抵达
完成接收请求和回复……
SimpleReplyChannel.EndTryReceiveRequest() //重复
SimpleReplyChannel.BeginTryReceiveRequest() //重复
完成接收请求和回复……
SimpleReplyChannel.EndTryReceiveRequest() //重复
SimpleReplyChannel.BeginTryReceiveRequest() //重复
完成接收请求和回复……
WCF - 绑定后续之自定义绑定的更多相关文章
- WCF - 自定义绑定
自定义绑定 当系统提供的某个绑定不符合服务的要求时,可使用 CustomBinding 类.所有绑定都是从绑定元素的有序集构造而来的.自定义绑定可以从一组系统提供的绑定元素生成,也可以包含用户定义的自 ...
- WCF扩展之实现ZeroMQ绑定和protocolBuffer消息编码(二)实现IRequestChannel(2016-03-15 12:35)
这是这个系列的第二篇,其他的文章请点击下列目录 WCF扩展之实现ZeroMQ绑定和protocolBuffer消息编码(一)概要设计 WCF扩展之实现ZeroMQ绑定和protocolBuffer消息 ...
- WCF 项目应用连载[8] - 绑定、服务、行为 大数据传输与限流 - 下 (ServiceThrottlingAttribute)
因为ORM的原因,对Attribute编程有一种情节..所以这节的出现,完全是因为在WCF对自定义Attribute的一种应用. WCF 项目应用连载[7] - 绑定.服务.行为 大数据传输与限流 - ...
- KNOCKOUTJS DOCUMENTATION-绑定(BINDINGS)-自定义绑定
除了ko内建的绑定,还可以自定义绑定,灵活地封装复杂的行为使之可重用. 自定义绑定 注册自定义绑定 向 ko.bindingHandles添加一个子属性来注册一个绑定. ko.bindingHandl ...
- Maven自定义绑定插件目标:创建项目的源码jar
<build> <plugins> <!-- 自定义绑定,创建项目的源码jar --> <plugin> <groupId>org.apac ...
- 背水一战 Windows 10 (20) - 绑定: DataContextChanged, UpdateSourceTrigger, 对绑定的数据做自定义转换
[源码下载] 背水一战 Windows 10 (20) - 绑定: DataContextChanged, UpdateSourceTrigger, 对绑定的数据做自定义转换 作者:webabcd 介 ...
- KnockoutJS 3.X API 第五章 高级应用(1) 创建自定义绑定
您不仅限于使用内置的绑定,如click,value绑定等,您可以创建自己的绑定. 这是如何控制视图模型如何与DOM元素进行交互,并且为您提供了大量的灵活性,以便于以复用的方式封装复杂的行为. 注册绑定 ...
- 5.Knockout.Js(自定义绑定)
前言 你可以创建自己的自定义绑定 – 没有必要非要使用内嵌的绑定(像click,value等).你可以你封装复杂的逻辑或行为,自定义很容易使用和重用的绑定.例如,你可以在form表单里自定义像grid ...
- 【Knockout】五、创建自定义绑定
概述 除了上一篇列出的KO内置的绑定类型(如value.text等),你也可以创建自定义绑定. 注册你的binding handler ko.bindingHandlers.yourBindingNa ...
随机推荐
- RPMForge——Quick Start build system
How to setup multimedia on CentOS-5 CentOS ships with basic sound support for audio content encoded ...
- Apache .htaccess Rewrite解决问号匹配的写法
如news.asp?id=123 需要把它定向到 news/123.html 这个用 RewriteRule 怎么写啊? RewriteRule ^news\.asp\?id=(\d+)$ news/ ...
- CoreProfiler/NanoProfiler
使用CoreProfiler/NanoProfiler实现跨平台&应用的整合性能调试 摘要 NanoProfiler是一个开源.NET性能调试类库,CoreProfiler是其.NET Cor ...
- RestKit:iOS开发必备,告别众多无聊代码
http://www.csdn.net/article/2014-04-15/2819312-RestKit-frameworkRestKit是一款专为iOS设计的Objective-C框架,旨在与R ...
- C连接MySQL数据库开发之Windows环境配置及测试
一.开发环境 Win8.1 64位.VS2013.MySQL5.5.3764位 MySQL安装目录为:C:\Program Files\MySQL\MySQL Server 5.5 二.配置工程环境 ...
- Contest20140906 反思
这次考试最大的失误就是把最简单的一道题RE了,原因是我在main()函数中开了一个2^19的数组,这种做法在linux下没有任何问题,然而放到windows下评测,就会出现栈溢出的错误. 单题总结: ...
- [BZOJ 1086] [SCOI2005] 王室联邦 【树分块】
题目链接:BZOJ - 1086 题目分析 这道题要求给树分块,使得每一块的大小在 [B, 3B] 之间,并且可以通过一个块外的节点(块根)使得整个块联通. 那么我们使用一种 DFS,维护一个栈,DF ...
- 【JavsScript】XMLHttpRequest2的进步之处
本文参考自:XMLHttpRequest2 新技巧 (重点保留demo,方便自己日后查阅) HTML5是现在web开发中的热点,虽然关于web app和local app一直有争论,但是从技术学习的角 ...
- html5--indexedDB
http://www.cnblogs.com/Johnny_Z/archive/2012/11/04/2753331.html http://database.51cto.com/art/201202 ...
- ios开发UI篇—在ImageView中添加按钮以及Tag的参数说明
ios开发UI篇—在ImageView中添加按钮以及Tag的参数说明 一.tag参数 一个视图通常都只有一个父视图,多个子视图,在开发中可以通过使用子视图的tag来取出对应的子视图.方法为Viewwi ...