Introduction
Sometimes in .NET programming, the general <appSettings> section of configuration is not enough to meet your needs. Fortunately, the .NET Framework provides a rich interface to create custom configuration sections for use in an application's configuration.
Background
This is the second of several articles walking through a WCF Router for an enterprise WCTP service. The sections are:
Part 1 - Overview
Part 2 - Extending web.config
Part 3 - Defining the Service Contracts
Part 4 - Implementing the Router
Part 5 - An Asynchronous Service Implementation
Part 6 - A Synchronous Service Implementation
Part 7 - Advanced Services
In this section, we show how a custom configuration section is created to store settings for all of the services that our Router will send information to.
Design
In the end, what we would like to have is a section in the XML configuration with something like the following:
<wctp>
<receivers>
<addReceiver name="Receiver1" intProperty="77" boolProperty="true" />
<addReceiver name="Receiver2" intProperty="114" boolProperty="false" >
</receivers>
</wctp>
This is done by using three custom classes which derive from base classes in the System.Configuration namespace. These are:
- A class derived from System.Configuration.ConfigurationSection, representing the <wctp> element.
- A class derived from System.Configuration.ConfigurationElementCollection, which represents the <receivers> and the ability to have the <addReceiver> elements.
- A class derived from System.Configuration.ConfigurationElement, which represents the property information contained within the <addReceiver> elements.
Let's look at these in detail.
WctpConfig
The WctpConfig class is our class which is derived from ConfigurationSection, and represents the root XML element of our custom configuration. Since it only contains a single collection, the code if quite small:
[ConfigurationProperty("receivers", IsDefaultCollection = false)]
[ConfigurationCollection(typeof(ReceiverCollection), AddItemName="addReceiver",
ClearItemsName="clearReceivers", RemoveItemName="removeReceiver")]
public ReceiverCollection Receivers
{
get
{
return (ReceiverCollection)(base["receivers"]);
}
}
Having the ability to use <clearReceivers> and <removeReceiver> elements allows use to machineToApplication settings, where some things could be defined in the machine.config file, or in other configuration files.
ReceiverCollection
The ReceiverCollection class is the class derived from ConfigurationElementCollection. It contains methods to get elements in the collection via integral index or string key, and also to add, remove, and clear the child elements.
This class is fairly generic and with minor modifications could easily be used in other projects.
ReceiverConfig
This is the class derived from ConfigurationElement. It contains the really custom code for our configuration tree. So let's look at what this is going to do for us.
In this class, we will have the information necessary to decide which possible Receiver to route WCTP messages to. So we would like it to have some very specific information:
- Name - This serves as the key for the ReceiverCollection element collection, but also must match a configured WCF endpoint.
- Priority - When multiple services otherwise match to receive a message, there must be some way to decide which one to send the message to. Prioritization is a good way to achieve this.
- Recipient Filter - This is a filter against the URI which the message is sent to. For example, a specific service might want everything sent to electric@contoso.com.
- Sender Filter - This is a filter against the URI of the radio device which sent the message. For example, if we wanted to insert a test service used for a group of test devices which all started with the address 602555121, we could use the filter "^602555121." to limit a service to only receive these messages.
- Format Handling - WCTP suppports two general formats, binary and text. Some services might only support one or the other of these two formats. So having configuration to specify this is a good idea.
- Exclusive Handling - It is possible to send a message to more than one service. This setting allows the configuration to specify whether or not sending to other, lower priority services should be done.
- One Way - WCF supports a myriad of lower layer protocols. Some services may not be available for synchronous communications, instead relying on specific lower layer functionality to hold the messages, such as MSMQ. This setting allows the configuration to specify whether or not a WCF Service Contract with (IsOneWay=true) operations.
Implementing these is fairly straightforward. Here is an example of the HandlesText property.
[ConfigurationProperty("text", IsRequired = false, DefaultValue = true)]
public bool HandlesText
{
get
{
return (bool)this["text"];
}
set
{
this["text"] = value;
}
}
Using the Collection
Skipping ahead a bit to the implementation of the WCTP HTTP Application, making use of the configuration is very easy. When deciding which WCF service to route a particular mesage to, a simple LINQ query can be executed to return an ordered list of prioritized potential services.
WctpConfig config = (WctpConfig)(ConfigurationManager.GetSection("WCTP"));
IEnumerable<WctpConfig> receivers;
if (payload.GetType() == typeof(string))
{
receivers = config.Receivers.OfType()
.Where(s => s.HandlesText)
.Where(s => Regex.Match(originator.senderID, s.SenderFilter).Success)
.Where(s => Regex.Match(recipient.recipientID, s.RecipientFilter).Success)
.OrderByDescending(s => s.Priority)
.ThenByDescending(s => s.ExclusiveHandler)
.ThenByDescending(s => s.OneWay);
}
else
{
receivers = config.Receivers.OfType()
.Where(s => s.HandlesBinary)
.Where(s => Regex.Match(originator.senderID, s.SenderFilter).Success)
.Where(s => Regex.Match(recipient.recipientID, s.RecipientFilter).Success)
.OrderByDescending(s => s.Priority)
.ThenByDescending(s => s.ExclusiveHandler)
.ThenByDescending(s => s.OneWay);
}
Isn't that nice!
Points of Interest
I find myself in awe more and more over the functionality contained within LINQ.
History
Mar 13, 2008 - Original Document