}
var traceMessage = builder.ToString();
Trace.WriteLine(traceMessage.Substring(0, traceMessage.Length - 1));
//Complete the Message
ReceiveContext receiveContext;
if (ReceiveContext.TryGet(incomingProperties, out receiveContext)) {
receiveContext.Complete(TimeSpan.FromSeconds(10.0d));
} else {
throw new InvalidOperationException("An exception occurred.");
} } }
catch (Exception ex) {
Trace.WriteLine(ex.Message);
} }
#endregion }
ListenUri Endpoint Behavior
As you will see ahead in the article, it’s easy to define a WCF-Custom receive location to read messages from a Service Bus queue or from a subscription. Nevertheless, in the previous section we have seen that when defining a WCF service endpoint to consume messages from a
subscription, you have to you have to specify the URL of the topic as the address of the service endpoint and the URL of the subscription as its listenUri. Now, when configuring a WCF receive location using the WCF-Custom adapter, there is a textbox for specifying the service endpoint address on the General tab of the configuration dialog, however there's no field to specify a value of the listenUri and ListenUriMode properties.
For this reason, I decided to create a custom endpoint behavior that at runtime can set these values for a WCF-Custom receive location. The first attempt was to use the
AddBindingParameters and ApplyDispatchBehavior methods exposed by the custom endpoint behavior to set the listenUri and ListenUriMode of the service endpoint passed as a parameter to both methods. However, this technique didn't work as expected.
Finally I solved the problem in the following way: I created a binding extension element class called ListenUriBehaviorExtensionElement to register the custom endpoint behavior in the
machine.config file. This component exposes a property called listenUri that allows a user to specify the URL of a subscription when configuring a WCF-Custom receive location.
At runtime, the ListenUriBehaviorExtensionElement component creates an instance of the ListenUriEndpointBehavior class. The AddBindingParameters method of the custom endpoint behavior replaces the original binding with a CustomBinding that contains the same binding elements and injects an instance of the ListenUriBindingElement at the top of the binding. This way, at runtime, the custom binding will be the first to execute. Finally, the BuildChannelListener method of the ListenUriBindingElement assigns the URL specified in the configuration of the receive location to the ListenUriBaseAddress property of the BindingContext and sets the value of its ListenUriMode property to Explicit. For you convenience, I included the code for the three classes below. Later in the article I'll show you how to use this component when defining a WCF-Custom receive location that receives messages from a Service Bus subscription.
ListenUriBehaviorExtensionElement Class
public class ListenUriBehaviorExtensionElement : IEndpointBehavior {
#region Private Constants
//***************************
// Constants
//***************************
private const string ListenUriName = "listenUri";
private const string IsTrackingEnabledName = "isTrackingEnabled";
private const string ListenUriDescription = "Gets or sets the URI at which the service endpoint listens.";
private const string IsTrackingEnabledDescription = "Gets or sets a value indicating whether tracking is enabled.";
#endregion
#region BehaviorExtensionElement Members //***************************
// Protected Methods
//***************************
/// <summary>
/// Creates a behavior extension based on the current configuration settings.
/// </summary>
/// <returns>The behavior extension.</returns>
protected override object CreateBehavior() {
return new ListenUriEndpointBehavior(ListenUri, IsTrackingEnabled);
}
/// <summary>
/// Gets the type of behavior.
/// </summary>
public override Type BehaviorType {
get {
return typeof(ListenUriEndpointBehavior);
} } #endregion
#region Public Properties /// <summary>
/// Gets or sets the URI at which the service endpoint listens.
/// </summary>
[ConfigurationProperty(ListenUriName, IsRequired = true)]
[SettingsDescription(ListenUriDescription)]
public string ListenUri {
get {
return (string)base[ListenUriName];
} set {
base[ListenUriName] = value;
} }
/// <summary>
/// Gets or sets a value indicating whether the message inspector is enabled.
/// </summary>
[ConfigurationProperty(IsTrackingEnabledName, DefaultValue = true, IsRequired = false)]
[SettingsDescription(IsTrackingEnabledDescription)]
public bool IsTrackingEnabled {
get {
return (bool)base[IsTrackingEnabledName];
set {
base[IsTrackingEnabledName] = value;
} }
#endregion }
ListenUriEndpointBehavior Class
public class ListenUriEndpointBehavior : IEndpointBehavior {
#region Private Constants //***************************
// Constants
//***************************
private const string ListerUriMessageFormat = "[ListenUriEndpointBehavior] ListenUri
= [{0}].";
#endregion
#region Public Constructors
private readonly string listenUri;
private readonly bool isTrackingEnabled;
#endregion
#region Public Constructors /// <summary>
/// Initializes a new instance of the ListenUriEndpointBehavior class.
/// </summary>
/// <param name="listenUri">The URI at which the service endpoint listens</param>
/// <param name="isTrackingEnabled">A boolean value indicating whether tracking is enabled</param>
public ListenUriEndpointBehavior(string listenUri, bool isTrackingEnabled) {
this.listenUri = listenUri;
this.isTrackingEnabled = isTrackingEnabled;
}
#endregion
#region IEndpointBehavior Members /// <summary>
/// Implement to pass data at runtime to bindings to support custom behavior.
/// <param name="endpoint">The endpoint to modify.</param>
/// <param name="bindingParameters">The objects that binding elements require to support the behavior.</param>
void IEndpointBehavior.AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
if (endpoint != null &&
!String.IsNullOrEmpty(listenUri)) {
// Read the binding elements from the original binding
var bindingElementCollection = endpoint.Binding.CreateBindingElements();
// Create an array of binding elements
var bindingElementArray = new BindingElement[bindingElementCollection.Count + 1];
// Add an instance of the ListenUriBindingElement as first binding element of the array
bindingElementArray[0] = new ListenUriBindingElement(listenUri);
// Copy the binding elements of the original binding to the array bindingElementCollection.CopyTo(bindingElementArray, 1);
// Create a custom binding with the same binding elements as the original // binding with the addition of the custom binding as first item
var customBinding = new CustomBinding(bindingElementArray) {
CloseTimeout = endpoint.Binding.CloseTimeout, OpenTimeout = endpoint.Binding.OpenTimeout, ReceiveTimeout = endpoint.Binding.ReceiveTimeout, SendTimeout = endpoint.Binding.SendTimeout, Name = endpoint.Binding.Name,
Namespace = endpoint.Binding.Namespace };
//Replace the original binding with the newly created binding endpoint.Binding = customBinding;
Trace.WriteLineIf(isTrackingEnabled,
string.Format(ListerUriMessageFormat, listenUri));
} }
/// <summary>
/// Implements a modification or extension of the client across an endpoint.
/// </summary>