Exploring WCF Services
LANGUAGES:
C#
TECHNOLOGIES:
.NET 3.5 | WCF
Custom Bindings: Part II
Creating and Configuring Custom Binding Types
By Michele Leroux Bustamante
This month s column explores how to create custom binding
types and how to programmatically and declaratively configure them for a
service endpoint.
In Custom
Bindings: Part I I explained how to create a custom binding element, and
how to programmatically and declaratively configure that element for an
endpoint. Creating custom binding elements is one way to inject custom
functionality into the channel stack, such as customizing the transport, the
message encoder, or adding new features. A CustomBinding instance is used to select
binding elements to configure the channel stack, but you can simplify reusable
configurations by creating a custom binding type that encapsulates the desired
features exposed by pre-existing or custom binding elements.
In this article, I ll explain how to create a custom binding
type, along with other types necessary to support declarative configuration.
Customizing Binding Configurations
You have several options when you configure service
endpoints and one of the standard bindings does not expose access to the
desired channel functionality, including:
- Use a CustomBinding to build the channel stack
by hand and reach into features exposed by individual binding elements.
- Create a custom BindingElement to add your own
custom functionality to the CustomBinding configuration.
- Extend one of the standard bindings to inject
custom functionality or to encapsulate default settings.
- Create a custom binding to encapsulate building
a collection of pre-existing or custom binding elements for the channel stack.
All these approaches can be configured programmatically or
declaratively. Of course, you must write additional code to support declarative
configuration for custom types, such as custom binding elements (as I discussed
in my last article) and custom bindings (to be discussed in this article).
In the following sections I ll first describe how to
create a custom binding type, then show you how to create a custom binding
element to configure the binding declaratively.
Creating a Custom Binding
Once you ve determined that you want to encapsulate a set
of channel features into a custom binding, you must decide if you want to
extend an existing standard binding and alter its initialization, or if you
want to create a completely new binding type.
By extending an existing standard binding you inherit all
its properties, but you can do interesting things, such as:
- Encapsulate the initialization of your preferred
default settings for the standard binding.
- Extend or alter the binding to introduce new
channel features with your own custom binding elements.
- Expose additional properties to be used to
configure those default settings and new channel features.
When you create a custom binding type, you have complete
control over the properties you want to expose, as well as choice of binding
elements that will be used to build the channel stack. In fact, when you create
a custom binding type, you ll typically do the following:
- Create a class that inherits the abstract binding
type.
- Define properties representative of information
you need to collect to build the channel stack.
- Supply useful constructors to initialize the
binding and its key properties.
- Provide an implementation for the abstract
method, CreateBindingElements, where you ll construct the binding elements that
compose the channel stack.
- Provide an implementation for the abstract
read-only property, Scheme, where you ll return the scheme supported by the
binding.
Let s take a look at these steps in the context of a
specific example.
Custom Binding Example: AssertEncryptionHttpBinding
Last month I explained how to create a custom transport
binding element that would allow you to configure WCF to receive UserName
credentials without encryption. The binding element,
AssertEncryptionHttpTransportBindingElement, extended the
HttpTransportBindingElement and injected a custom ISecurityCapabilities that
asserts support for encryption to fake a secure channel. The purpose of this is
to support scenarios where an SSL processing load balancer intercepts messages
and handles decryption prior to forwarding messages to the appropriate WCF
service. This is necessary only in this scenario because, by default, WCF
disallows sending credentials without encryption.
Figure 1 illustrates the requirements of this scenario.
Essentially, a WCF client may send credentials by transport or message over an
SSL connection, but the target WCF service must receive those credentials
without encryption because the load balancer will process the SSL encryption
and forward the message unencrypted.
Figure 1: Security semantics for the
SSL load balancer scenario.
Instead of creating a CustomBinding that uses this custom
transport binding element, this time I ll create a custom binding type that
encapsulates adding the appropriate transport binding element, along with
setting up other required binding elements. Because the security features of
this binding are limited to a few scenarios, I will not extend BasicHttpBinding
or WSHttpBinding. Instead, I ll create a new type, AssertEncryptionHttpBinding,
that directly extends the binding type. Listing One shows
the complete listing for this new binding.
Selecting Properties for AssertEncryptionHttpBinding
Let s start by discussing the new properties exposed by
this binding. The choice of properties I exposed is directly linked to the
information I wanted to gather to properly initialize each binding element to
compose the channel stack. The binding base type provides an implementation for
the common timeout settings (OpenTimeout, CloseTimeout, SendTimeout, and
ReceiveTimeout); thus, the custom binding inherits these properties. Beyond
these, I chose to expose the properties described in Figure 2 some of which
are common to most bindings, others not.
|
Binding Property
|
Usage
|
|
MessageEncoding
|
Sets the type of message encoder based on the
WSMessageEncoding enumeration with the options Text or Mtom.
|
|
MessageVersion
|
Sets the format for SOAP messaging and WS-Addressing
based on the MessageVersion type with options: Soap11, Soap11WSAddressing10,
Soap11WSAddressingAugust2004, Soap12, Soap12WSAddressing10, or
Soap12WSAddressingAugust2004.
|
|
MaxReceivedMessageSize
|
Sets the size quota for received messages.
|
|
ReaderQuotas
|
Sets the size quota for strings, arrays, and other
reader quotas.
|
|
SecurityMode
|
Sets the chosen security features for the binding based
on a custom enumeration, AssertEncryptionHttpSecurityMode, with options:
None, UserNameOverTransport, or UserNameOverMessage.
|
Figure 2: New
properties exposed by AssertEncryptionHttpBinding.
These property settings are used to initialize the
transport, encoder, and security features of the binding.
I exposed the MessageEncoding property to be consistent
with other HTTP bindings that support Text and Mtom encoding, using the
WSMessageEncoding enumeration type. This value is used to choose between
TextMessageEncodingBindingElement and MtomMessageEncodingBindingElement when
CreateBindingElements is called to produce the binding element collection for
the channel stack.
Quota-related properties including MaxReceivedMessageSize
and the ReaderQuotas collection allow for customizing these settings, as this
is frequently necessary to support passing large files, arrays, or strings. The
value for MaxReceivedMessageSize is used to initialize the equivalent property
on the transport binding element, which, in this case, is an instance of the
custom binding element described last time (AssertEncryptionHttpTransportBindingElement).
The value for ReaderQuotas is used to initialize the same on the two message
encoder instances, so that both are correctly initialized prior to building the
binding element collection.
By exposing a MessageVersion property, the binding can be
initialized using the BasicHttpBinding or WSHttpBinding equivalent, or some
other value that is required for interoperability. This property is based on
the MessageVersion type and, like ReaderQuotas, its value is used to initialize
the two message encoder instances. One interesting thing to point out is that
the new keyword is used to hide the binding base type s implementation of
MessageVersion, which is read-only. This has no impact on the polymorphic
behavior of this property because the base implementation relies on the binding
element collection to return the correct value from the selected message
encoder.
The SecurityMode property for this custom binding
implementation is based on a custom enumeration type,
AssertEncryptionHttpSecurityMode, as shown here:
public enum AssertEncryptionHttpSecurityMode
{
None,
UserNameOverTransport,
UserNameOverMessage
}
This binding supports three scenarios for passing
credentials: no credentials, basic username, and password credentials passed in
HTTP headers and username and password passed in the message.
The table in Figure 3 summarizes a typical set of
SecurityMode and MessageVersion combinations for the
AssertEncryptionHttpBinding and how those settings would relate to the
standing binding equivalent the client application would use to send messages.
This is important, because it governs how the CreateBindingElements override
will choose and configure binding elements.
|
SecurityMode
|
MessageVersion
|
Standard Binding
Equivalent
|
|
None
|
Soap11
|
BasicHttpBinding + BasicHttpSecurityMode.Transport + HttpClientCredentialType.None
|
|
None
|
Soap12WSAddressing10
|
WSHttpBinding + disable secure sessions and negotiation +
SecurityMode.Transport + HttpClientCredentialType.None
|
|
UserNameOverTransport
|
Soap11
|
BasicHttpBinding + BasicHttpSecurityMode.Transport + HttpClientCredentialType.Basic
|
|
UserNameOverTransport
|
Soap12WSAddressing10
|
WSHttpBinding + disable secure sessions and negotiation +
SecurityMode.Transport + HttpClientCredentialType.Basic
|
|
UserNameOverMessage
|
Soap11
|
BasicHttpBinding + BasicHttpSecurityMode.TransportWithMessageCredential
+ BasicHttpMessageCredentialType.UserName
|
|
UserNameOverMessage
|
Soap12WSAddressing10
|
WSHttpBinding + disable secure sessions and negotiation +
SecurityMode.TransportWithMessageCredential + MessageCredentialType.UserName
|
Figure 3: Standard
binding equivalent settings for common AssertEncryptionHttpBinding SecurityMode
and MessageVersion settings.
Remember that the AssertEncryptionHttpBinding assumes the
communication channel will be unencrypted, because the purpose of the binding
is to wrap the use of the AssertEncryptionHttpTransportBindingElement to
receive unencrypted credentials. As such, the SecurityMode property need only
collect information about the type of credentials that will be used to
authenticate.
Creating Binding Elements for AssertEncryptionHttpBinding
A binding type is the type through which the communication
channel is built. This is done by constructing a collection of binding elements,
including transport, message encoder, and other channel features, such as
security. You can use pre-existing binding elements or custom binding elements
to build the channel stack so long as there is a message encoder and a
transport channel. I discussed this in my last article.
Aside from exposing properties listed in the previous
section, the AssertEncryptionHttpBinding type also provides overrides for
abstract members of the base binding type, and implements
IBindingRuntimePreferences. Implementing IBindingRuntimePreferences is optional,
yet common to most bindings. This contract is used to indicate if requests can
be handled synchronously or asynchronously at the service. Usually asynchronous
is preferred so the implementation of the read-only property,
ReceiveSynchronously, usually reports False (as shown in Listing One).
AssertEncryptionHttpBinding provides an override for the
read-only Scheme property, and for CreateBindingElements. Scheme always returns
HTTP, as the purpose of the binding is to receive credentials without
encryption. The implementation for CreateBindingElements is really the heart of
this custom binding.
CreateBindingElements is called to build a collection of
binding elements that will be used to build the channel stack. The binding
relies on properties to select the appropriate binding elements, and to
initialize properties on those binding elements. You should expose properties
for any property you want to allow control over for the underlying binding
elements. In Listing One you can see the complete implementation of
CreateBindingElements. This list summarizes what is going on in there:
- If message security is used, a
SecurityBindingElement is created to support UserName credentials passed in the
message, protected by the transport. CreateUserNameOverTransportBindingElement
is the way to programmatically create this element for a CustomBinding.
- Depending on the setting for MessageEncoding,
the appropriate Text or Mtom message encoder is added to the binding elements
collection.
- The same transport binding element is always
used (AssertEncryptionHttpTransportBindingElement).
- If transport security is used, security is
initialized on the transport binding element instead. This is handled by the
private method GetTransport, which sets the transport s authentication scheme
to AuthenticationSchemes.Basic if UserName credentials are to be passed in transport
headers.
This binding exposes three constructors. Two are used to
programmatically initialize the bindings using defaults for security, or
explicitly passing a value for the SecurityMode property. The following
illustrates how to construct the binding programmatically and initialize
relevant settings to pass larger messages, arrays, and strings using SOAP 1.1
and Mtom encoding:
AssertEncryptionHttpBinding binding = new
AssertEncryptionHttpBinding(
AssertEncryptionHttpSecurityMode.UserNameOverMessage);
binding.MaxReceivedMessageSize = 100000;
binding.ReaderQuotas.MaxArrayLength = 100000;
binding.ReaderQuotas.MaxStringContentLength = 30000;
binding.ReceiveTimeout = new TimeSpan(0, 20, 0);
binding.MessageVersion = MessageVersion.Soap11;
binding.MessageEncoding = WSMessageEncoding.Mtom;
Recall that the ReceiveTimeout is a property inherited
from the binding base type, and that MessageVersion hides the base type
implementation because it is read-only.
To configure the binding declaratively, I created a custom
StandardBindingElement and StandardBindingCollectionElement, which I ll discuss
next.
Declaratively Configuring AssertEncryptionHttpBinding
You must supply a custom binding configuration element to
support declarative configuration for a custom binding. To achieve declarative
configuration for AssertEncryptionHttpBinding I created the
AssertEncryptionHttpBindingElement, which extends StandardBindingElement (as
shown in Listing Two).
The following list breaks down the functionality of the
custom binding configuration element and its base types:
- At the core is the ConfigurationElement type,
which provides serialization and deserialization functionality for any
configuration element.
- StandardBindingElement extends ConfigurationElement
to add properties common to most bindings, including timeout properties
(OpenTimeout, CloseTimeout, SendTimeout, ReceiveTimeout) and the Name property
for naming the binding element.
- AssertEncryptionHttpBindingElement exposes
additional configuration properties, which are then used to configure the binding
type, AssertEncryptionHttpBinding. Usually there is a synergy between the
properties that a custom binding type exposes and custom configuration element
properties (to support equivalent declarative configuration).
It helps to have a picture of the desired XML
configuration in terms of elements and attributes before you determine the
properties you ll expose on the binding configuration element type. Figure 4
shows examples of several <assertEncryptionHttpBinding> configurations.
Each example sets the various properties exposed by the binding:
MaxReceivedMessageSize, MessageEncoding, MessageVersion, SecurityMode, and
common values for ReaderQuotas.
<bindings>
<assertEncryptionHttpBinding>
<binding
name="noSecurity" maxReceivedMessageSize="100000"
securityMode="None"
messageEncoding="Text" messageVersion="Soap11">
<readerQuotas
maxArrayLength="100000" maxStringContentLength="30000"/>
</binding>
<binding
name="userNameOverTransport"
maxReceivedMessageSize="100000"
securityMode="UserNameOverTransport"
messageEncoding="Text"
messageVersion="Soap12">
<readerQuotas
maxArrayLength="100000" maxStringContentLength="30000"/>
</binding>
<binding
name="userNameOverMessage" maxReceivedMessageSize="100000"
securityMode="UserNameOverMessage"
messageEncoding="Text"
messageVersion="Soap12WSAddressing10">
<readerQuotas
maxArrayLength="100000" maxStringContentLength="30000"/>
</binding>
</assertEncryptionHttpBinding>
</bindings>
Figure 4: Examples
of declarative configuration for AssertEncryptionHttpBinding.
To achieve this configuration, the custom binding
configuration element must expose a property for each setting and decorate it
with the ConfigurationElementAttribute, as shown here for
MaxReceivedMessageSize:
[ConfigurationProperty("maxReceivedMessageSize",
DefaultValue = 0x10000L)]
[LongValidator(MinValue = 1L)]
public long MaxReceivedMessageSize
You will typically supply a name for the configuration
element, as well as a default value. Optionally, you can use one of the
predefined ConfigurationValidatorAttribute types, such as the
LongValidatorAttribute used for MaxReceivedMessageSize.
In the case of ReaderQuotas, the property itself is also a
type of ConfigurationElement (XmlDictionaryReaderQuotasElement), which in turn
exposes properties decorated with the ConfigurationElementAttribute:
[ConfigurationProperty("readerQuotas")]
public XmlDictionaryReaderQuotasElement
ReaderQuotas {get; set;}
public sealed class XmlDictionaryReaderQuotasElement :
ConfigurationElement
{...}
You can create your own nested XML definitions for the
binding configuration by referencing custom ConfigurationElement types as
children.
The get and set implementation for configuration
properties typically use the base ConfigurationElement indexer, as shown here
for the MessageEncoding property (enumerations can simply be cast on return):
[ConfigurationProperty("messageEncoding", DefaultValue
= 0)]
public WSMessageEncoding MessageEncoding
{
get
{
return
(WSMessageEncoding)base["messageEncoding"];
}
set
{
base["messageEncoding"] = value.ToString();
}
}
Aside from defining configuration properties, the custom
binding configuration element type also provides the following overrides:
- BindingElementType: A read-only property
override that should return the correct binding element type.
- InitializeFrom: A method override that
initializes the binding configuration element from a binding type instance.
- ApplyConfiguration: A method override that
initializes a binding type instance from configuration settings.
- Properties: A read-only property override that
builds a ConfigurationPropertyCollection with a list of properties for the base
type indexer. Each property can have a name, type, and, optionally, a default
value, a validator, and configuration options based on the
ConfigurationPropertyOptions collection the latter of which is useful for
marking required properties most frequently used.
ApplyConfiguration is called when you associate a
declarative binding configuration with an endpoint, like those shown in Figure
4. A few more steps are required to trigger this association. First, a custom
StandardBindingCollectionElement must be defined to associate the binding type
with the custom binding configuration element type. Figure 5 shows the
implementation for the AssertEncryptionHttpBindingCollectionElement, which
extends StandardBindingCollectionElement.
public class AssertEncryptionHttpBindingCollectionElement:
StandardBindingCollectionElement<AssertEncryptionHttpBinding,
AssertEncryptionHttpBindingElement>
{
public const string
BindingCollectionElementName =
"assertEncryptionHttpBinding";
public static
AssertEncryptionHttpBindingCollectionElement
GetBindingCollectionElement()
{
AssertEncryptionHttpBindingCollectionElement
bindingCollectionElement = null;
BindingsSection
bindingsSection =
ConfigurationManager.GetSection("system.serviceModel/bindings")
as BindingsSection;
if (bindingsSection !=
null)
{
bindingCollectionElement = bindingsSection[
AssertEncryptionHttpBindingCollectionElement.BindingCollectionElementName]
as
AssertEncryptionHttpBindingCollectionElement;
}
return
bindingCollectionElement;
}
}
Figure 5:
AssertEncryptionHttpBindingCollectionElement implementation.
Following suit with other implementations of standard
binding collection elements, I exposed a static method (GetBindingCollectionElement)
to do the work of loading the appropriate configuration section. This method is
called by the custom binding configuration element during initialization.
Next, the <extensions> section of <system.serviceModel>
must include a <bindingExtensions> element that associates the bindings
section with the custom StandardBindingElementCollection type. The following
associates the <assertEncryptionHttpBinding> elements shown in Figure 4
with the AssertEncryptionHttpBindingCollectionElement shown in Figure 5:
<extensions>
<bindingExtensions>
<add
name="assertEncryptionHttpBinding"
type="CustomSecurity.AssertEncryptionHttpBinding
CollectionElement,
CustomSecurity" />
</bindingExtensions>
</extensions>
When the ServiceHost initializes endpoints that use <assertEncryptionHttpBinding>
declarations, AssertEncryptionHttpBindingCollectionElement is used to find the
configuration element type to initialize with configuration values, and the
correct Binding type to initialize from that configuration.
Note: You also can use
a utility supplied with the WCF Samples in the Windows SDK,
ConfigurationCodeGenerator.exe, to generate code to support declarative
configuration of your custom bindings or binding elements. This is described on
MSDN at http://msdn.microsoft.com/en-us/library/aa395201.aspx.
Conclusion
In this two-article series I provided a practical example
for creating a custom binding element, and one for creating a custom binding.
My goal was to provide you with a simple example that did not dive into the
depths of custom channel creation that involves channel listeners and channel
factories which would take a lot more than a few short articles to describe
effectively. Developers frequently need to customize existing binding elements
or standard bindings in this way; this example has illustrated how easy it can
be to create and configure custom binding elements and custom bindings.
There are some very rich examples of custom bindings,
binding elements, channel listeners, and channel factories available in the
Windows SDK for .NET 3.5, including the popular chunking channel and router
examples. See my code download for information on where to find those specific
samples in addition to my own.
In the next article for this column I ll begin to explore
new features forthcoming in WCF 4.0. Get ready!
Download the samples
for this article at http://www.dasblonde.net/downloads/asppromar09.zip.
Michele Leroux
Bustamante is Chief Architect of IDesign Inc., Microsoft Regional Director
for San Diego, and Microsoft MVP for Connected Systems. At IDesign Michele
provides training, mentoring, and high-end architecture consulting services
focusing on Web services, scalable and secure architecture design for .NET,
federated security scenarios, Web services, interoperability, and globalization
architecture. She is a member of the International .NET Speakers Association
(INETA), a frequent conference presenter, conference chair for SD West, and is
frequently published in several major technology journals. Michele also is on
the board of directors for IASA (International Association of Software
Architects), and a Program Advisor to UCSD Extension. Her latest book is Learning WCF (O Reilly, 2007; updated in 2008);
visit her book blog at http://www.thatindigogirl.com.
Reach her at mailto:mlb@idesign.net, or
visit http://www.idesign.net and her main
blog at http://www.dasblonde.net.
Additional Resources
Begin Listing One AssertEncryptionHttpBinding
implementation
public class AssertEncryptionHttpBinding :
Binding,
IBindingRuntimePreferences
{
public
AssertEncryptionHttpSecurityMode
SecurityMode { get; set; }
public WSMessageEncoding
MessageEncoding {get; set;}
public new MessageVersion
MessageVersion
{
get
{
if
(this.MessageEncoding == WSMessageEncoding.Text)
return
this.TextEncoding.MessageVersion;
else
return
this.MtomEncoding.MessageVersion;
}
set
{
this.TextEncoding.MessageVersion = value;
this.MtomEncoding.MessageVersion = value;
}
}
public long
MaxReceivedMessageSize
{
get
{
return
this.Transport.MaxReceivedMessageSize;
}
set
{
this.Transport.MaxReceivedMessageSize = value;
}
}
public
XmlDictionaryReaderQuotas ReaderQuotas
{
get
{
if
(this.MessageEncoding == WSMessageEncoding.Text)
return
this.TextEncoding.ReaderQuotas;
else
return this.MtomEncoding.ReaderQuotas;
}
set
{
value.CopyTo(this.TextEncoding.ReaderQuotas);
value.CopyTo(this.MtomEncoding.ReaderQuotas);
}
}
private
AssertEncryptionHttpTransportBindingElement
Transport { get; set; }
private
TextMessageEncodingBindingElement
TextEncoding { get; set; }
private
MtomMessageEncodingBindingElement
MtomEncoding { get; set; }
public
AssertEncryptionHttpBinding()
:
this(AssertEncryptionHttpSecurityMode.None)
{
}
public
AssertEncryptionHttpBinding(
AssertEncryptionHttpSecurityMode
securityMode)
{
this.SecurityMode =
securityMode;
this.MessageEncoding =
WSMessageEncoding.Text;
this.TextEncoding = new
TextMessageEncodingBindingElement();
this.MtomEncoding = new
MtomMessageEncodingBindingElement();
this.MessageVersion=
MessageVersion.Soap12WSAddressing10;
this.Transport = new
AssertEncryptionHttpTransportBindingElement();
}
public
AssertEncryptionHttpBinding(string
configurationName): this()
{
AssertEncryptionHttpBindingElement bindingElement =
AssertEncryptionHttpBindingCollectionElement.
GetBindingCollectionElement().Bindings[configurationName]
as
AssertEncryptionHttpBindingElement;
if (bindingElement ==
null)
throw new
ConfigurationErrorsException(
string.Format("Binding
configuration element
missing: {0} in {1}", configurationName,
AssertEncryptionHttpBindingCollectionElement.
BindingCollectionElementName));
bindingElement.ApplyConfiguration(this);
}
public override
BindingElementCollection
CreateBindingElements()
{
BindingElementCollection bindingElements =
new BindingElementCollection();
// if passing
credentials via message security,
// add a security
element
TransportSecurityBindingElement
transportSecurityElement = null;
if (this.SecurityMode
==
AssertEncryptionHttpSecurityMode.UserNameOverMessage)
{
transportSecurityElement = SecurityBindingElement.
CreateUserNameOverTransportBindingElement();
}
if
(transportSecurityElement != null)
bindingElements.Add(transportSecurityElement);
// add a message
encoder element
if
(this.MessageEncoding == WSMessageEncoding.Text)
bindingElements.Add(this.TextEncoding);
else if
(this.MessageEncoding == WSMessageEncoding.Mtom)
bindingElements.Add(this.MtomEncoding);
// add a transport
element
bindingElements.Add(this.GetTransport());
return bindingElements;
}
private
TransportBindingElement GetTransport()
{
if (this.SecurityMode
==
AssertEncryptionHttpSecurityMode.UserNameOverTransport)
{
this.Transport.AuthenticationScheme =
System.Net.AuthenticationSchemes.Basic;
}
return this.Transport;
}
public override string
Scheme
{
get { return
this.Transport.Scheme; }
}
#region
IBindingRuntimePreferences Members
public bool
ReceiveSynchronously
{
get { return false; }
}
#endregion
}
End Listing One
Begin Listing Two AssertEncryptionHttpBindingElement
implementation
public class AssertEncryptionHttpBindingElement:
StandardBindingElement
{
[ConfigurationProperty("messageEncoding",
DefaultValue = 0)]
public WSMessageEncoding
MessageEncoding
{
get
{
return
(WSMessageEncoding)base["messageEncoding"];
}
set
{
base["messageEncoding"] = value.ToString();
}
}
[ConfigurationProperty("maxReceivedMessageSize",
DefaultValue = 0x10000L), LongValidator(MinValue
= 1L)]
public long
MaxReceivedMessageSize
{
get
{
return
(long)base["maxReceivedMessageSize"];
}
set
{
base["maxReceivedMessageSize"] = value;
}
}
public const string
DefaultMessageVersion =
"Soap11WSAddressing10";
[ConfigurationProperty("messageVersion", DefaultValue =
AssertEncryptionHttpBindingElement.DefaultMessageVersion)]
public MessageVersion
MessageVersion
{
get
{
string messageVersion
= (string)base["messageVersion"];
System.Reflection.PropertyInfo propertyInfo =
typeof(MessageVersion).GetProperty(messageVersion);
return
(MessageVersion)propertyInfo.GetValue(null, null);
}
set
{
base["messageVersion"] = value.ToString();
}
}
[ConfigurationProperty("readerQuotas")]
public
XmlDictionaryReaderQuotasElement ReaderQuotas
{
get
{
return
(XmlDictionaryReaderQuotasElement)base[
"readerQuotas"];
}
}
[ConfigurationProperty("securityMode", DefaultValue =
AssertEncryptionHttpSecurityMode.None)]
public
AssertEncryptionHttpSecurityMode SecurityMode
{
get
{
return
(AssertEncryptionHttpSecurityMode)base[
"securityMode"];
}
set
{
base["securityMode"] = value;
}
}
protected override Type
BindingElementType
{
get { return
typeof(AssertEncryptionHttpBinding); }
}
protected override void
InitializeFrom(
System.ServiceModel.Channels.Binding
binding)
{
base.InitializeFrom(binding);
AssertEncryptionHttpBinding
assertEncryptionHttpBinding
= (AssertEncryptionHttpBinding)binding;
this.MessageEncoding =
assertEncryptionHttpBinding.MessageEncoding;
this.MessageVersion =
assertEncryptionHttpBinding.MessageVersion;
this.MaxReceivedMessageSize =
assertEncryptionHttpBinding.MaxReceivedMessageSize;
this.SecurityMode =
assertEncryptionHttpBinding.SecurityMode;
}
protected override void
OnApplyConfiguration(
System.ServiceModel.Channels.Binding
binding)
{
AssertEncryptionHttpBinding assertEncryptionHttpBinding
= (AssertEncryptionHttpBinding)binding;
assertEncryptionHttpBinding.MessageEncoding =
this.MessageEncoding;
assertEncryptionHttpBinding.MessageVersion =
this.MessageVersion;
if (this.ReaderQuotas
!= null)
{
if
(this.ReaderQuotas.MaxDepth != 0)
{
assertEncryptionHttpBinding.ReaderQuotas.MaxDepth =
this.ReaderQuotas.MaxDepth;
}
if
(this.ReaderQuotas.MaxStringContentLength != 0)
{
assertEncryptionHttpBinding.ReaderQuotas.
MaxStringContentLength
= this.ReaderQuotas.
MaxStringContentLength;
}
if
(this.ReaderQuotas.MaxArrayLength != 0)
{
assertEncryptionHttpBinding.ReaderQuotas.
MaxArrayLength =
this.ReaderQuotas.
MaxArrayLength;
}
if
(this.ReaderQuotas.MaxBytesPerRead != 0)
{
assertEncryptionHttpBinding.ReaderQuotas.
MaxBytesPerRead
= this.ReaderQuotas.
MaxBytesPerRead;
}
if
(this.ReaderQuotas.MaxNameTableCharCount != 0)
{
assertEncryptionHttpBinding.ReaderQuotas.
MaxNameTableCharCount
= this.ReaderQuotas.
MaxNameTableCharCount;
}
}
assertEncryptionHttpBinding.SecurityMode =
this.SecurityMode;
}
private
ConfigurationPropertyCollection m_properties;
protected override
ConfigurationPropertyCollection Properties
{
get
{
ConfigurationPropertyCollection
properties = null;
if (this.m_properties
== null)
{
properties =
base.Properties;
properties.Add(new
ConfigurationProperty(
"messageEncoding",
typeof(WSMessageEncoding),
WSMessageEncoding.Text,
null, null,
ConfigurationPropertyOptions.None));
properties.Add(new
ConfigurationProperty(
"maxReceivedMessageSize",
typeof(long), 0x10000L,
null, new
LongValidator(1L, 0x7fffffffffffffffL,
false), ConfigurationPropertyOptions.None));
properties.Add(new
ConfigurationProperty(
"messageVersion",
typeof(string),
AssertEncryptionHttpBindingElement.
DefaultMessageVersion,
null, null,
ConfigurationPropertyOptions.None));
properties.Add(new
ConfigurationProperty(
"readerQuotas",
typeof(
XmlDictionaryReaderQuotasElement),
null, null,
null, ConfigurationPropertyOptions.None));
properties.Add(new
ConfigurationProperty(
"securityMode", typeof(
AssertEncryptionHttpSecurityMode),
AssertEncryptionHttpSecurityMode.None,
null,
null, ConfigurationPropertyOptions.None));
this.m_properties =
properties;
}
return
this.m_properties;
}
}
}
End Listing Two