WCF技术内幕之绑定

    绑定类型是开发人员控制WCF程序与其他消息交互的主要手段。从功能上看,绑定创建了通道工厂或通道侦听器的堆栈对象。在设计模式中,一个绑定就是一个工厂。在服务模型层和通道层中,绑定在服务模型层是可见的,它创建的对象作用与通道层。

绑定对象模型

    所有的绑定类型都继承自抽象类型System.ServiceModel.Channels.Binding,因此,所有的绑定都具有相同的特性。与通道工厂、通道侦听器和通道不同,绑定类型没有复杂的类型层次关系。绑定类型定义如下:

// System.ServiceModel.Channels.Binding
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;

[__DynamicallyInvokable]
public abstract class Binding : IDefaultCommunicationTimeouts
{
	private TimeSpan closeTimeout = ServiceDefaults.CloseTimeout;

	private string name;

	private string namespaceIdentifier;

	private TimeSpan openTimeout = ServiceDefaults.OpenTimeout;

	private TimeSpan receiveTimeout = ServiceDefaults.ReceiveTimeout;

	private TimeSpan sendTimeout = ServiceDefaults.SendTimeout;

	internal const string DefaultNamespace = "http://tempuri.org/";

	[DefaultValue(typeof(TimeSpan), "00:01:00")]
	[__DynamicallyInvokable]
	public TimeSpan CloseTimeout
	{
		[__DynamicallyInvokable]
		get
		{
			return this.closeTimeout;
		}
		[__DynamicallyInvokable]
		set
		{
			if (value < TimeSpan.Zero)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SR.GetString("SFxTimeoutOutOfRange0")));
			}
			if (TimeoutHelper.IsTooLarge(value))
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SR.GetString("SFxTimeoutOutOfRangeTooBig")));
			}
			this.closeTimeout = value;
		}
	}

	[__DynamicallyInvokable]
	public string Name
	{
		[__DynamicallyInvokable]
		get
		{
			if (this.name == null)
			{
				this.name = base.GetType().Name;
			}
			return this.name;
		}
		[__DynamicallyInvokable]
		set
		{
			if (string.IsNullOrEmpty(value))
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("value", SR.GetString("SFXBindingNameCannotBeNullOrEmpty"));
			}
			this.name = value;
		}
	}

	[__DynamicallyInvokable]
	public string Namespace
	{
		[__DynamicallyInvokable]
		get
		{
			return this.namespaceIdentifier;
		}
		[__DynamicallyInvokable]
		set
		{
			if (value == null)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
			}
			if (value.Length > 0)
			{
				NamingHelper.CheckUriProperty(value, "Namespace");
			}
			this.namespaceIdentifier = value;
		}
	}

	[DefaultValue(typeof(TimeSpan), "00:01:00")]
	[__DynamicallyInvokable]
	public TimeSpan OpenTimeout
	{
		[__DynamicallyInvokable]
		get
		{
			return this.openTimeout;
		}
		[__DynamicallyInvokable]
		set
		{
			if (value < TimeSpan.Zero)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SR.GetString("SFxTimeoutOutOfRange0")));
			}
			if (TimeoutHelper.IsTooLarge(value))
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SR.GetString("SFxTimeoutOutOfRangeTooBig")));
			}
			this.openTimeout = value;
		}
	}

	[DefaultValue(typeof(TimeSpan), "00:10:00")]
	[__DynamicallyInvokable]
	public TimeSpan ReceiveTimeout
	{
		[__DynamicallyInvokable]
		get
		{
			return this.receiveTimeout;
		}
		[__DynamicallyInvokable]
		set
		{
			if (value < TimeSpan.Zero)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SR.GetString("SFxTimeoutOutOfRange0")));
			}
			if (TimeoutHelper.IsTooLarge(value))
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SR.GetString("SFxTimeoutOutOfRangeTooBig")));
			}
			this.receiveTimeout = value;
		}
	}

	[__DynamicallyInvokable]
	public abstract string Scheme
	{
		[__DynamicallyInvokable]
		get;
	}

	[__DynamicallyInvokable]
	public MessageVersion MessageVersion
	{
		[__DynamicallyInvokable]
		get
		{
			return this.GetProperty<MessageVersion>(new BindingParameterCollection());
		}
	}

	[DefaultValue(typeof(TimeSpan), "00:01:00")]
	[__DynamicallyInvokable]
	public TimeSpan SendTimeout
	{
		[__DynamicallyInvokable]
		get
		{
			return this.sendTimeout;
		}
		[__DynamicallyInvokable]
		set
		{
			if (value < TimeSpan.Zero)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SR.GetString("SFxTimeoutOutOfRange0")));
			}
			if (TimeoutHelper.IsTooLarge(value))
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SR.GetString("SFxTimeoutOutOfRangeTooBig")));
			}
			this.sendTimeout = value;
		}
	}

	[__DynamicallyInvokable]
	protected Binding()
	{
		this.name = null;
		this.namespaceIdentifier = "http://tempuri.org/";
	}

	[__DynamicallyInvokable]
	protected Binding(string name, string ns)
	{
		if (string.IsNullOrEmpty(name))
		{
			throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("name", SR.GetString("SFXBindingNameCannotBeNullOrEmpty"));
		}
		if (ns == null)
		{
			throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("ns");
		}
		if (ns.Length > 0)
		{
			NamingHelper.CheckUriParameter(ns, "ns");
		}
		this.name = name;
		this.namespaceIdentifier = ns;
	}

	[__DynamicallyInvokable]
	public IChannelFactory<TChannel> BuildChannelFactory<TChannel>(params object[] parameters)
	{
		return this.BuildChannelFactory<TChannel>(new BindingParameterCollection(parameters));
	}

	[__DynamicallyInvokable]
	public virtual IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingParameterCollection parameters)
	{
		this.EnsureInvariants();
		BindingContext bindingContext = new BindingContext(new CustomBinding(this), parameters);
		IChannelFactory<TChannel> channelFactory = bindingContext.BuildInnerChannelFactory<TChannel>();
		bindingContext.ValidateBindingElementsConsumed();
		this.ValidateSecurityCapabilities(channelFactory.GetProperty<ISecurityCapabilities>(), parameters);
		return channelFactory;
	}

	private void ValidateSecurityCapabilities(ISecurityCapabilities runtimeSecurityCapabilities, BindingParameterCollection parameters)
	{
		ISecurityCapabilities property = this.GetProperty<ISecurityCapabilities>(parameters);
		if (SecurityCapabilities.IsEqual(property, runtimeSecurityCapabilities))
		{
			return;
		}
		throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("SecurityCapabilitiesMismatched", this)));
	}

	public virtual IChannelListener<TChannel> BuildChannelListener<TChannel>(params object[] parameters) where TChannel : class, IChannel
	{
		return this.BuildChannelListener<TChannel>(new BindingParameterCollection(parameters));
	}

	public virtual IChannelListener<TChannel> BuildChannelListener<TChannel>(Uri listenUriBaseAddress, params object[] parameters) where TChannel : class, IChannel
	{
		return this.BuildChannelListener<TChannel>(listenUriBaseAddress, new BindingParameterCollection(parameters));
	}

	public virtual IChannelListener<TChannel> BuildChannelListener<TChannel>(Uri listenUriBaseAddress, string listenUriRelativeAddress, params object[] parameters) where TChannel : class, IChannel
	{
		return this.BuildChannelListener<TChannel>(listenUriBaseAddress, listenUriRelativeAddress, new BindingParameterCollection(parameters));
	}

	public virtual IChannelListener<TChannel> BuildChannelListener<TChannel>(Uri listenUriBaseAddress, string listenUriRelativeAddress, ListenUriMode listenUriMode, params object[] parameters) where TChannel : class, IChannel
	{
		return this.BuildChannelListener<TChannel>(listenUriBaseAddress, listenUriRelativeAddress, listenUriMode, new BindingParameterCollection(parameters));
	}

	public virtual IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingParameterCollection parameters) where TChannel : class, IChannel
	{
		UriBuilder uriBuilder = new UriBuilder(this.Scheme, DnsCache.MachineName);
		return this.BuildChannelListener<TChannel>(uriBuilder.Uri, string.Empty, ListenUriMode.Unique, parameters);
	}

	public virtual IChannelListener<TChannel> BuildChannelListener<TChannel>(Uri listenUriBaseAddress, BindingParameterCollection parameters) where TChannel : class, IChannel
	{
		return this.BuildChannelListener<TChannel>(listenUriBaseAddress, string.Empty, ListenUriMode.Explicit, parameters);
	}

	public virtual IChannelListener<TChannel> BuildChannelListener<TChannel>(Uri listenUriBaseAddress, string listenUriRelativeAddress, BindingParameterCollection parameters) where TChannel : class, IChannel
	{
		return this.BuildChannelListener<TChannel>(listenUriBaseAddress, listenUriRelativeAddress, ListenUriMode.Explicit, parameters);
	}

	public virtual IChannelListener<TChannel> BuildChannelListener<TChannel>(Uri listenUriBaseAddress, string listenUriRelativeAddress, ListenUriMode listenUriMode, BindingParameterCollection parameters) where TChannel : class, IChannel
	{
		this.EnsureInvariants();
		BindingContext bindingContext = new BindingContext(new CustomBinding(this), parameters, listenUriBaseAddress, listenUriRelativeAddress, listenUriMode);
		IChannelListener<TChannel> channelListener = bindingContext.BuildInnerChannelListener<TChannel>();
		bindingContext.ValidateBindingElementsConsumed();
		this.ValidateSecurityCapabilities(channelListener.GetProperty<ISecurityCapabilities>(), parameters);
		return channelListener;
	}

	[__DynamicallyInvokable]
	public bool CanBuildChannelFactory<TChannel>(params object[] parameters)
	{
		return this.CanBuildChannelFactory<TChannel>(new BindingParameterCollection(parameters));
	}

	[__DynamicallyInvokable]
	public virtual bool CanBuildChannelFactory<TChannel>(BindingParameterCollection parameters)
	{
		BindingContext bindingContext = new BindingContext(new CustomBinding(this), parameters);
		return bindingContext.CanBuildInnerChannelFactory<TChannel>();
	}

	public bool CanBuildChannelListener<TChannel>(params object[] parameters) where TChannel : class, IChannel
	{
		return this.CanBuildChannelListener<TChannel>(new BindingParameterCollection(parameters));
	}

	public virtual bool CanBuildChannelListener<TChannel>(BindingParameterCollection parameters) where TChannel : class, IChannel
	{
		BindingContext bindingContext = new BindingContext(new CustomBinding(this), parameters);
		return bindingContext.CanBuildInnerChannelListener<TChannel>();
	}

	[__DynamicallyInvokable]
	public abstract BindingElementCollection CreateBindingElements();

	[__DynamicallyInvokable]
	public T GetProperty<T>(BindingParameterCollection parameters) where T : class
	{
		BindingContext bindingContext = new BindingContext(new CustomBinding(this), parameters);
		return bindingContext.GetInnerProperty<T>();
	}

	private void EnsureInvariants()
	{
		this.EnsureInvariants(null);
	}

	internal void EnsureInvariants(string contractName)
	{
		BindingElementCollection bindingElementCollection = this.CreateBindingElements();
		TransportBindingElement transportBindingElement = null;
		int i;
		for (i = 0; i < bindingElementCollection.Count; i++)
		{
			transportBindingElement = (((Collection<BindingElement>)bindingElementCollection)[i] as TransportBindingElement);
			if (transportBindingElement != null)
			{
				break;
			}
		}
		if (transportBindingElement == null)
		{
			if (contractName == null)
			{
				throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("CustomBindingRequiresTransport", this.Name)));
			}
			throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("SFxCustomBindingNeedsTransport1", contractName)));
		}
		if (i != bindingElementCollection.Count - 1)
		{
			throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("TransportBindingElementMustBeLast", this.Name, transportBindingElement.GetType().Name)));
		}
		if (string.IsNullOrEmpty(transportBindingElement.Scheme))
		{
			throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("InvalidBindingScheme", transportBindingElement.GetType().Name)));
		}
		if (this.MessageVersion != null)
		{
			return;
		}
		throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("MessageVersionMissingFromBinding", this.Name)));
	}

	internal void CopyTimeouts(IDefaultCommunicationTimeouts source)
	{
		this.CloseTimeout = source.CloseTimeout;
		this.OpenTimeout = source.OpenTimeout;
		this.ReceiveTimeout = source.ReceiveTimeout;
		this.SendTimeout = source.SendTimeout;
	}

	[EditorBrowsable(EditorBrowsableState.Never)]
	public bool ShouldSerializeName()
	{
		return this.Name != base.GetType().Name;
	}

	[EditorBrowsable(EditorBrowsableState.Never)]
	public bool ShouldSerializeNamespace()
	{
		return this.Namespace != "http://tempuri.org/";
	}
}

BindingElement类型

    BindingElement是一个工厂对象。更确切地说,BindingElement类型定义了返回通道工厂和通道侦听器的方法。创建BindingElement对象的主要方式是通过Binding.CreateBindingElements方法。对于通道工厂、通道侦听器和通道,没有万能的BindingElement类型。WCF类型系统包含许多BindingElement的子类型,而每个都表示WCF支持的消息功能。BindingElement类型的定义如下所示:

// System.ServiceModel.Channels.BindingElement
using System.ServiceModel;
using System.ServiceModel.Channels;

[__DynamicallyInvokable]
public abstract class BindingElement
{
	[__DynamicallyInvokable]
	protected BindingElement()
	{
	}

	[__DynamicallyInvokable]
	protected BindingElement(BindingElement elementToBeCloned)
	{
	}

	[__DynamicallyInvokable]
	public abstract BindingElement Clone();

	[__DynamicallyInvokable]
	public virtual IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
	{
		if (context == null)
		{
			throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
		}
		return context.BuildInnerChannelFactory<TChannel>();
	}

	public virtual IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context) where TChannel : class, IChannel
	{
		if (context == null)
		{
			throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
		}
		return context.BuildInnerChannelListener<TChannel>();
	}

	[__DynamicallyInvokable]
	public virtual bool CanBuildChannelFactory<TChannel>(BindingContext context)
	{
		if (context == null)
		{
			throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
		}
		return context.CanBuildInnerChannelFactory<TChannel>();
	}

	public virtual bool CanBuildChannelListener<TChannel>(BindingContext context) where TChannel : class, IChannel
	{
		if (context == null)
		{
			throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
		}
		return context.CanBuildInnerChannelListener<TChannel>();
	}

	[__DynamicallyInvokable]
	public abstract T GetProperty<T>(BindingContext context) where T : class;

	internal T GetIndividualProperty<T>() where T : class
	{
		return this.GetProperty<T>(new BindingContext(new CustomBinding(), new BindingParameterCollection()));
	}

	internal virtual bool IsMatch(BindingElement b)
	{
		return false;
	}
}

    BindingElement的查询机制

       BindingElement的查询机制和通道、通道工厂及通道侦听器一样。BindingElement的查询机制依赖于BindingContext中对下一个BindingElement对象的代理查询。下面就是BindingElement子类型查询机制的实现,这里展示了如何使用BindingContext参数委托查询:

 

    public override T GetProperty<T>(BindingContext context)
    {
        if(context == null)
        {
            throw new ArgumentNullException("context");
        }
        //委托所有的查询,除了其他绑定的一些查询功能
        if (typeof(T) != typeof(SomeCapabilility))
        {
            //通过BindingContext利用其他绑定元素的查询机制
            return context.GetInnerProperty<T>();
        }
        //BindingElement元素里的一个域成员可以放回这个功能
        return (T)this.someCapability;
    }

TransportBindingElement类型

    最难应用到Binding上的规则是,如何让CreateBindingElements返回的BindingElement对象可以创建传输通道工厂或通道侦听器。理论看起来很合理,因为消息终结点只有在支持特定形式的传输时才有意义。由于这个原因,WCF类型系统定义了一个抽象类型System.ServicerModel.Channels.TransportBindingElement。TransportBindingElement类型定义了几个只有通道工厂或通道侦听器需要的成员,但是TransportBindingElement继承自BindingElement类型。

    因为BindingElement集合是创建通道侦听器和通道工厂堆栈的蓝图,所以,TransportBindingElement必须出现在集合的末端。Binding和BindingContext类型都强化了这一规则。

BindingContext类型

    绑定和BindingElement对象把绝大部分创建通道工厂堆栈和通道侦听器堆栈的工厂委托给System.ServiceModel.Channels.BindingContext类型来做。当创建、测试或查询通道工厂堆栈或通道侦听器堆栈时,BindingContext类型提供上下文信息给BindingElement集合对象。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值