Custom Bindings: Part II
Michele Leroux Bustamante explores how to create custom binding types and how to programmatically and declaratively configure them for a service endpoint.
October 30, 2009
RELATED: "Choosing the Right Web Service Binding" and "MVC Model Binding"
In "CustomBindings: Part I" I explained how to create a custom binding element, andhow to programmatically and declaratively configure that element for anendpoint. Creating custom binding elements is one way to inject customfunctionality into the channel stack, such as customizing the transport, themessage encoder, or adding new features. A CustomBinding instance is used to selectbinding elements to configure the channel stack, but you can simplify reusableconfigurations by creating a custom binding type that encapsulates the desiredfeatures exposed by pre-existing or custom binding elements.
In this article, I ll explain how to create a custom bindingtype, along with other types necessary to support declarative configuration.
Customizing Binding Configurations
You have several options when you configure serviceendpoints and one of the standard bindings does not expose access to thedesired 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 ordeclaratively. Of course, you must write additional code to support declarativeconfiguration for custom types, such as custom binding elements (as I discussedin my last article) and custom bindings (to be discussed in this article).
In the following sections I ll first describe how tocreate a custom binding type, then show you how to create a custom bindingelement to configure the binding declaratively.
Creating a Custom Binding
Once you ve determined that you want to encapsulate a setof channel features into a custom binding, you must decide if you want toextend an existing standard binding and alter its initialization, or if youwant to create a completely new binding type.
By extending an existing standard binding you inherit allits 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 completecontrol over the properties you want to expose, as well as choice of bindingelements that will be used to build the channel stack. In fact, when you createa 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 aspecific example.
Custom Binding Example: AssertEncryptionHttpBinding
Last month I explained how to create a custom transportbinding element that would allow you to configure WCF to receive UserNamecredentials without encryption. The binding element,AssertEncryptionHttpTransportBindingElement, extended theHttpTransportBindingElement and injected a custom ISecurityCapabilities thatasserts support for encryption to fake a secure channel. The purpose of this isto support scenarios where an SSL processing load balancer intercepts messagesand handles decryption prior to forwarding messages to the appropriate WCFservice. This is necessary only in this scenario because, by default, WCFdisallows sending credentials without encryption.
Figure 1 illustrates the requirements of this scenario.Essentially, a WCF client may send credentials by transport or message over anSSL connection, but the target WCF service must receive those credentialswithout encryption because the load balancer will process the SSL encryptionand forward the message unencrypted.
Figure 1: Security semantics for theSSL load balancer scenario.
Instead of creating a CustomBinding that uses this customtransport binding element, this time I ll create a custom binding type thatencapsulates adding the appropriate transport binding element, along withsetting up other required binding elements. Because the security features ofthis binding are limited to a few scenarios, I will not extend BasicHttpBindingor WSHttpBinding. Instead, I ll create a new type, AssertEncryptionHttpBinding,that directly extends the binding type. Listing One showsthe complete listing for this new binding.
Selecting Properties for AssertEncryptionHttpBinding
Let s start by discussing the new properties exposed bythis binding. The choice of properties I exposed is directly linked to theinformation I wanted to gather to properly initialize each binding element tocompose the channel stack. The binding base type provides an implementation forthe common timeout settings (OpenTimeout, CloseTimeout, SendTimeout, andReceiveTimeout); thus, the custom binding inherits these properties. Beyondthese, I chose to expose the properties described in Figure 2 some of whichare 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: Newproperties exposed by AssertEncryptionHttpBinding.
These property settings are used to initialize thetransport, encoder, and security features of the binding.
I exposed the MessageEncoding property to be consistentwith other HTTP bindings that support Text and Mtom encoding, using theWSMessageEncoding enumeration type. This value is used to choose betweenTextMessageEncodingBindingElement and MtomMessageEncodingBindingElement whenCreateBindingElements is called to produce the binding element collection forthe channel stack.
Quota-related properties including MaxReceivedMessageSizeand the ReaderQuotas collection allow for customizing these settings, as thisis frequently necessary to support passing large files, arrays, or strings. Thevalue for MaxReceivedMessageSize is used to initialize the equivalent propertyon the transport binding element, which, in this case, is an instance of thecustom binding element described last time (AssertEncryptionHttpTransportBindingElement).The value for ReaderQuotas is used to initialize the same on the two messageencoder instances, so that both are correctly initialized prior to building thebinding element collection.
By exposing a MessageVersion property, the binding can beinitialized using the BasicHttpBinding or WSHttpBinding equivalent, or someother value that is required for interoperability. This property is based onthe MessageVersion type and, like ReaderQuotas, its value is used to initializethe two message encoder instances. One interesting thing to point out is thatthe new keyword is used to hide the binding base type s implementation ofMessageVersion, which is read-only. This has no impact on the polymorphicbehavior of this property because the base implementation relies on the bindingelement collection to return the correct value from the selected messageencoder.
The SecurityMode property for this custom bindingimplementation is based on a custom enumeration type,AssertEncryptionHttpSecurityMode, as shown here:
public enum AssertEncryptionHttpSecurityMode{ None, UserNameOverTransport, UserNameOverMessage}
This binding supports three scenarios for passingcredentials: no credentials, basic username, and password credentials passed inHTTP headers and username and password passed in the message.
The table in Figure 3 summarizes a typical set ofSecurityMode and MessageVersion combinations for theAssertEncryptionHttpBinding and how those settings would relate to thestanding binding equivalent the client application would use to send messages.This is important, because it governs how the CreateBindingElements overridewill 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: Standardbinding equivalent settings for common AssertEncryptionHttpBinding SecurityModeand MessageVersion settings.
Remember that the AssertEncryptionHttpBinding assumes thecommunication channel will be unencrypted, because the purpose of the bindingis to wrap the use of the AssertEncryptionHttpTransportBindingElement toreceive unencrypted credentials. As such, the SecurityMode property need onlycollect information about the type of credentials that will be used toauthenticate.
Creating Binding Elements for AssertEncryptionHttpBinding
A binding type is the type through which the communicationchannel is built. This is done by constructing a collection of binding elements,including transport, message encoder, and other channel features, such assecurity. You can use pre-existing binding elements or custom binding elementsto build the channel stack so long as there is a message encoder and atransport channel. I discussed this in my last article.
Aside from exposing properties listed in the previoussection, the AssertEncryptionHttpBinding type also provides overrides forabstract members of the base binding type, and implementsIBindingRuntimePreferences. Implementing IBindingRuntimePreferences is optional,yet common to most bindings. This contract is used to indicate if requests canbe handled synchronously or asynchronously at the service. Usually asynchronousis preferred so the implementation of the read-only property,ReceiveSynchronously, usually reports False (as shown in Listing One).
AssertEncryptionHttpBinding provides an override for theread-only Scheme property, and for CreateBindingElements. Scheme always returnsHTTP, as the purpose of the binding is to receive credentials withoutencryption. The implementation for CreateBindingElements is really the heart ofthis custom binding.
CreateBindingElements is called to build a collection ofbinding elements that will be used to build the channel stack. The bindingrelies on properties to select the appropriate binding elements, and toinitialize properties on those binding elements. You should expose propertiesfor any property you want to allow control over for the underlying bindingelements. In Listing One you can see the complete implementation ofCreateBindingElements. 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 toprogrammatically initialize the bindings using defaults for security, orexplicitly passing a value for the SecurityMode property. The followingillustrates how to construct the binding programmatically and initializerelevant settings to pass larger messages, arrays, and strings using SOAP 1.1and 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 inheritedfrom the binding base type, and that MessageVersion hides the base typeimplementation because it is read-only.
To configure the binding declaratively, I created a customStandardBindingElement and StandardBindingCollectionElement, which I ll discussnext.
Declaratively Configuring AssertEncryptionHttpBinding
You must supply a custom binding configuration element tosupport declarative configuration for a custom binding. To achieve declarativeconfiguration for AssertEncryptionHttpBinding I created theAssertEncryptionHttpBindingElement, which extends StandardBindingElement (asshown in Listing Two).
The following list breaks down the functionality of thecustom 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 XMLconfiguration in terms of elements and attributes before you determine theproperties you ll expose on the binding configuration element type. Figure 4shows examples of several configurations.Each example sets the various properties exposed by the binding:MaxReceivedMessageSize, MessageEncoding, MessageVersion, SecurityMode, andcommon values for ReaderQuotas.
Figure 4: Examplesof declarative configuration for AssertEncryptionHttpBinding.
To achieve this configuration, the custom bindingconfiguration element must expose a property for each setting and decorate itwith the ConfigurationElementAttribute, as shown here forMaxReceivedMessageSize:
[ConfigurationProperty("maxReceivedMessageSize", DefaultValue = 0x10000L)][LongValidator(MinValue = 1L)]public long MaxReceivedMessageSize
You will typically supply a name for the configurationelement, as well as a default value. Optionally, you can use one of thepredefined ConfigurationValidatorAttribute types, such as theLongValidatorAttribute used for MaxReceivedMessageSize.
In the case of ReaderQuotas, the property itself is also atype of ConfigurationElement (XmlDictionaryReaderQuotasElement), which in turnexposes 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 thebinding configuration by referencing custom ConfigurationElement types aschildren.
The get and set implementation for configurationproperties typically use the base ConfigurationElement indexer, as shown herefor 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 custombinding 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 adeclarative binding configuration with an endpoint, like those shown in Figure4. A few more steps are required to trigger this association. First, a customStandardBindingCollectionElement must be defined to associate the binding typewith the custom binding configuration element type. Figure 5 shows theimplementation for the AssertEncryptionHttpBindingCollectionElement, whichextends StandardBindingCollectionElement.
public class AssertEncryptionHttpBindingCollectionElement: StandardBindingCollectionElement{ 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 standardbinding collection elements, I exposed a static method (GetBindingCollectionElement)to do the work of loading the appropriate configuration section. This method iscalled by the custom binding configuration element during initialization.
Next, the section of must include a element that associates the bindingssection with the custom StandardBindingElementCollection type. The followingassociates the elements shown in Figure 4with the AssertEncryptionHttpBindingCollectionElement shown in Figure 5:
When the ServiceHost initializes endpoints that use declarations, AssertEncryptionHttpBindingCollectionElement is used to find theconfiguration element type to initialize with configuration values, and thecorrect Binding type to initialize from that configuration.
Note: You also can usea utility supplied with the WCF Samples in the Windows SDK,ConfigurationCodeGenerator.exe, to generate code to support declarativeconfiguration of your custom bindings or binding elements.
Conclusion
In this two-article series I provided a practical examplefor 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 thedepths of custom channel creation that involves channel listeners and channelfactories which would take a lot more than a few short articles to describeeffectively. Developers frequently need to customize existing binding elementsor standard bindings in this way; this example has illustrated how easy it canbe 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 theWindows SDK for .NET 3.5, including the popular chunking channel and routerexamples. See my code download for information on where to find those specificsamples in addition to my own.
In the next article for this column I ll begin to explorenew features forthcoming in WCF 4.0. Get ready!
Download the samplesfor this article at http://www.dasblonde.net/downloads/asppromar09.zip.
Begin Listing One AssertEncryptionHttpBindingimplementation
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 AssertEncryptionHttpBindingElementimplementation
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
Read more about:
MicrosoftAbout the Author
You May Also Like