Leveraging WCF Extensibility to Simplify and Secure Integration of BizTalk Server with Windows Azure AppFabric Service Bus

This post is intended to drill down into a simple and powerful technique that enables the developers to take advantage of the WCF extensibility and make it easier to configure common friction points between an on-premise BizTalk Server environment and Windows Azure AppFabric Service Bus. All information provided in this article is based on a successful customer project. The concepts discussed in this post have been validated and proven in a real-world solution, and will hopefully serve as beneficial lessons learned for the community.

Background

When building hybrid distributed applications that involve on-premise and geo-separate elements of the end-to-end architecture, the means of connectivity become imperative. The Windows Azure AppFabric Service Bus is a first-class choice for addressing the connectivity requirements at the Internet scale as it makes it possible to connect on- and off-premises applications together regardless of their locations. The application services that register themselves on the Service Bus can be discovered and accessed across any network topology, regardless whether or not these services are separated by firewalls, NAT gateways or other technically challenging network boundaries.

BizTalk Server provides full support for exposing on-premise service endpoints through the AppFabric Service Bus. It also enables consuming the WCF services listening on the Service Bus anywhere in the world. In order to seamlessly support this type of connectivity, BizTalk leverages the custom WCF bindings that are included into and installed as part of the AppFabric Service Bus SDK such as NetTcpRelayBinding and NetEventRelayBinding. The configuration requirements for the above WCF bindings comprise of setting up the appropriate location URI of a Service Bus endpoint, configuring the correct transport security settings and other parameters that play important role in defining the behavioral, operational and meta-informational characteristics on a service endpoint exposed via the Service Bus.

In most cases, a BizTalk solution that connects to a Service Bus endpoint will be required to authenticate itself before it can participate in message exchange. At present, the most common way of configuring a BizTalk WCF-Custom Receive Location or a Send Port to talk to the Service Bus is through using the Shared Secret authentication mode which is essentially an easy-to-use form of username/password authentication:

In this context, even though the choice of supported authentication modes is likely to be expanded in the future, a few specific challenges may be sustainable if not approached and addressed from the beginning. These challenges can be generalized to the following extent.

The Challenges

In a complex composite application that involves both a BizTalk and a Cloud element of the solution architecture, the number of friction points that define how these solution elements interoperate with each other can be substantial. For example, there may well be a large number of Receive Ports configured in the BizTalk environment, each servicing different needs and exposing distinct service contracts. In addition, the on-premise BizTalk solution may be communicating through the Service Bus with a number of services each requiring a dedicated Send Port configured with WCF-Custom adapter and appropriate Service Bus WCF binding.

Having to specify the authentication mode and access credentials for each Service Bus endpoint and essentially “hard-code” these details inside the Receive Location or Send Port configuration may be considered as unmanageable given the large number of instances where these parameters need to be applied. The generic On-Ramp and Off-Ramp concepts introduced by the ESB Toolkit could help keep the number of BizTalk ports to a minimum, essentially through enabling to accept all incoming traffic via a single Receive Location and going out via a single dynamic port. Whilst this option may sound like a viable alternative, it’s not that uncommon for a BizTalk solution to require a separate Receive Location for each exposed service contract or to rely on static ports since dynamic ports may introduce unwanted degree of complexity in pure messaging scenarios.

Consider the following solution design where a BizTalk Server application exposes and consumes multiple services from a single AppFabric Service Bus namespace. Each of these connectivity points stores its own configuration in isolation leading to duplicating the security credentials in multiple places:

In summary, whenever there is a need to have multiple connectivity points between BizTalk and AppFabric Service Bus, there is a real possibility where one could end up in a situation in which serviceability of the entire solution may become challenging as configuration data will be spread in many places.

The second, and perhaps most important aspect of managing the configuration data in the above scenario is security. As things stand at the moment, the shared secret credentials are stored inside the BizTalk’s WCF adapter configuration, which in turn is securely kept inside an Enterprise Single Sign-On (SSO) encrypted data vault. However, this story would not have been complete without being subject to the following: the credentials can be easily fetched by any BizTalk administrator and therefore it may not play well in some enterprise environments with tightened security.

Bottom line, it would be highly desirable to reduce headache when maintaining complex composite application environments and be respectful to any security policies that may be in place. To this end, consolidating the application configuration into a common, centrally-managed secure repository is becoming crucial. Supplementary to this requirement, various application components need to be taught how to retrieve and apply the configuration settings at runtime.

Looking back at the above challenge with having multiple instances of the same Service Bus transport credentials specified in different locations in clear text, let’s explore how extensibility in WCF makes it remarkably easy to solve this challenge and apply centrally stored configuration settings to a given Receive or Send WCF port at runtime.

The Solution

Although the Windows Communication Foundation (WCF) application model is designed to solve the larger part of the communication and interoperability requirements in the world of modern distributed applications, there could be other scenarios which the out-of-the-box WCF functionality do not support. With this reason in mind, the WCF extensibility model is intended to support custom scenarios by enabling the developers to modify system behavior at every level in the WCF messaging stack.

In particular, custom behavior extensions represent a powerful mechanism which allows to modify default behaviors and add customizations that inspect and validate service configuration or modify runtime characteristics in the WCF client and service applications.

Out of the 4 supported types of behaviors in WCF, the endpoint behavior represents a separate interest in light of the above challenge. When implemented, it enables to dynamically configure a Receive or Send port when these are initialized during the messaging runtime construction process.

In essence, a custom behavior extension will make it possible to invoke the user code whenever BizTalk Messaging runtime initializes a WCF Receive Port and hooks it up to the AppFabric Service Bus messaging infrastructure. The same principle applies to BizTalk WCF Send Ports. Once gets called, the user code will be in a position to reach out to a central configuration store, retrieve security credentials and dynamically configure the corresponding WCF bindings responsible for communication with the Service Bus.

The following sections discuss how we implemented a WCF custom behavior extension to automatically configure all WCF ports in a BizTalk solution with Service Bus credentials stored centrally and securely in the configuration database.

Implementing WCF Custom Endpoint Behavior

To follow along, download the full sample code from the MSDN Code Gallery.

In the first step, we created a new class deriving from IEndpointBehavior. All implementations of this interface are able to examine, modify, or extend some aspect of endpoint-wide execution at the application level for either WCF client or service applications.

public class SelfConfigurableServiceBusEndpointBehavior : IEndpointBehavior
{
    /// Initializes a new instance of the SelfConfigurableServiceBusEndpointBehavior class.
    public SelfConfigurableServiceBusEndpointBehavior(string endpointName)
    {
        ServiceBusEndpointName = endpointName;
    }

    /// Gets or sets the value of the mandatory property containing the name of the AppFabric Service Bus endpoint
    /// definition in the application configuration.
    public string ServiceBusEndpointName
    {
        get;
        private set;
    }

    /// Enables to pass data at runtime to bindings to support custom behavior.
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
        // Trace the method entry event.
        var callToken = TraceManager.CustomComponent.TraceIn(endpoint.Name, endpoint.ListenUri);

        // Get the Service Bus endpoint definition by its name from the current application configuration.
        ServiceBusEndpointInfo sbEndpointInfo = ApplicationConfiguration.Current.ServiceBusSettings.Endpoints[ServiceBusEndpointName];

        // Check if we found a definition.
        if (sbEndpointInfo != null)
        {
            // Trace an information event telling that we have found the Service Bus endpoint definition.
            TraceManager.CustomComponent.TraceInfo(TraceLogMessages.ApplyingServiceBusEndpointConfiguration, ServiceBusEndpointName, endpoint.Name, sbEndpointInfo.ServiceNamespace, sbEndpointInfo.ServicePath, sbEndpointInfo.RelayMode);

            // Look for a TransportClientEndpointBehavior implementation in the collection of registered behaviors.
            var credentialsBehaviour = endpoint.Behaviors.Find<TransportClientEndpointBehavior>();

            // Check if TransportClientEndpointBehavior was registered.
            if (credentialsBehaviour != null)
            {
                // Configure the TransportClientEndpointBehavior with credentials captured from the application
// configuration.
credentialsBehaviour.CredentialType = TransportClientCredentialType.SharedSecret; credentialsBehaviour.Credentials.SharedSecret.IssuerName = sbEndpointInfo.IssuerName; credentialsBehaviour.Credentials.SharedSecret.IssuerSecret = sbEndpointInfo.IssuerSecret; // Check if we need to perform any changes at the WCF binding level. var relayBinding = endpoint.Binding as NetTcpRelayBinding; // If it is a NetTcpRelayBinding, we need to ensure that its ConnectionMode property matches the one
// defined in the application configuration.
if (relayBinding != null) { // Configure ConnectionMode with the value from the ServiceBusEndpointInfo configuration object. switch (sbEndpointInfo.RelayMode) { case ServiceBusRelayMode.Relayed: relayBinding.ConnectionMode = TcpRelayConnectionMode.Relayed; break; case ServiceBusRelayMode.RelayedHybrid: relayBinding.ConnectionMode = TcpRelayConnectionMode.Hybrid; break; } } } } else { // Trace a warning event, do not throw an exception as Service Bus binding will report on missing
// credentials anyway.
TraceManager.CustomComponent.TraceWarning(TraceLogMessages.ServiceBusEndpointDefinitionNotFound, ServiceBusEndpointName); } // Trace an event indicating that we are done. TraceManager.CustomComponent.TraceOut(callToken); } /// Enables modifications or extensions of the client across an endpoint. public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { // No implementation is required. } /// Enables modifications or extensions of the service across an endpoint. public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { // No implementation is required. } /// Enables to validate and confirm that the endpoint meets some intended criteria. public void Validate(ServiceEndpoint endpoint) { // Trace the method entry event. var callToken = TraceManager.CustomComponent.TraceIn(endpoint.Name, endpoint.ListenUri); // Look for a TransportClientEndpointBehavior implementation in the collection of registered behaviors. var credentialsBehaviour = endpoint.Behaviors.Find<TransportClientEndpointBehavior>(); // If not found, create a new instance of TransportClientEndpointBehavior and register it in the behavior
// collection.
if (null == credentialsBehaviour) { endpoint.Behaviors.Add(new TransportClientEndpointBehavior()); } // Trace an event indicating that we are done. TraceManager.CustomComponent.TraceOut(callToken); } }

Implementing WCF Behavior Extension Configuration Element

The second step was to implement a custom BehaviorExtensionElement that enables to customize the custom WCF endpoint behavior with user-defined configuration settings. These settings will appear in a configuration file as well as on the Transport Properties dialog box in the BizTalk Server Administration Console. The BehaviorExtensionElement implementation is also responsible for creating and initialing the instances of our custom behavior based on  configuration settings specified.

/// Implements an extension element for a custom WCF endpoint behavior.
public class SelfConfigurableServiceBusEndpointBehaviorElement : BehaviorExtensionElement
{
    /// Defines the name of the configuration property as appears in the config file or BizTalk Admin console.
    private const string ServiceBusEndpointNameProperty = "serviceBusEndpointName";

    /// Gets or sets the value of the mandatory property containing the name of the AppFabric Service Bus endpoint
    /// definition in the application configuration.
    [ConfigurationProperty(ServiceBusEndpointNameProperty, IsRequired = true)]
    public string ServiceBusEndpointName
    {
        get { return (string)(base[ServiceBusEndpointNameProperty]); }
        set { base[ServiceBusEndpointNameProperty] = value; }
    }

    /// Returns the underlying type of a custom behavior.
    public override Type BehaviorType
    {
        get { return typeof(SelfConfigurableServiceBusEndpointBehavior); }
    }

    /// Creates a behavior extension based on the current configuration settings.
    protected override object CreateBehavior()
    {
        return new SelfConfigurableServiceBusEndpointBehavior(this.ServiceBusEndpointName);
    }
}

Registering WCF Custom Endpoint Behavior

The next step was to make the custom behavior available for a BizTalk Server administrator to use. In order for the BizTalk Administration Console to load and display a custom BehaviorExtensionElement, it must be registered in machine.config. In addition, the component must have a strong name and be registered in the Global Assembly Cache (GAC) of the appropriate .NET Framework Runtime (either v2.0 or 4.0).

The following example shows the machine.config configuration file with a registration entry for the above custom BehaviorExtensionElement implementation.

<?xml version="1.0" encoding="UTF-8"?>
<!--
Note that changes will need to be made in all copies of machine.config:

C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\CONFIG\machine.config
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config
-->
<configuration>
  <!-- ... -->
  <!-- There is plenty of other XML content here -->
  <!-- ... -->
  <system.serviceModel>
    <extensions>
      <behaviorExtensions>
        <!-- ... -->
        <!-- There is plenty of other registrations here -->
        <!-- ... -->
        <add name="selfConfigurableServiceBusEndpointBehavior" type="MyCompany.MyProject.BizTalk.Extensions. SelfConfigurableServiceBusEndpointBehaviorElement, MyCompany.MyProject.BizTalk.Extensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      </behaviorExtensions>
      <!-- ... -->
      <!-- There is plenty of other XML content here -->
      <!-- ... -->
    </extensions>
  </system.serviceModel>
</configuration>

Configuring BizTalk Receive/Send Ports

Once the registration process was completed, the next step was to activate the custom endpoint behavior on all WCF ports used for communication with the AppFabric Service Bus. The Behavior tab on the WCF-Custom Transport Properties dialog enables adding a new behavior from the list of registered extensions:

The custom behavior makes the existing TransportClientEndpointBehavior definition obsolete. The new selfConfigurableServiceBusEndpointBehavior element automatically adds and configures a TransportClientEndpointBehavior, consequently the former can be removed from the port configuration.

Now that the BizTalk WCF-Custom port was configured with a new custom behavior, it’s time to explain the purpose of the serviceBusEndpointName property exposed in the custom behavior configuration.

Establishing Relationships with Configuration Source

As referenced above, the custom behavior extension element residing in the SelfConfigurableServiceBusEndpointBehaviorElement class provides a configuration property called serviceBusEndpointName. Simply put, this parameter is just a lookup key inside the application configuration source. In essence, it establishes a relationship between a BizTalk port and its configuration stored elsewhere, for example in an UDDI registry or custom database. It is the responsibility of the custom behavior implementation to understand how to map the specified key to the configuration data as well as how to retrieve and decrypt (if necessary) the shared secret credentials.

Over the course of several years, the implementation patterns for storing, managing and securing application configuration have evolved in different directions and have seen a variety of evolutionary  techniques ranging from de-centralized configuration files to enterprise-class discoverable application repositories. Although there is no single “silver bullet” as it relates to application configuration management, most BizTalk developers would prefer to secure their configuration data by taking advantage of the Enterprise SSO configuration store, either in stand-alone mode or in conjunction with other popular application frameworks such as Enterprise Library.

Whilst any specific guidance related to application configuration management is out of scope of this article, it would be worthwhile to complete the story and highlight how we approached the implementation of a WCF custom behavior extension in our customer engagement and plugged it into a centralized configuration repository.

First, we implemented a C# class deriving from SerializableConfigurationSection which defined the Service Bus endpoint configuration settings including service namespace, service path and shared secret credentials for each service endpoint used by our BizTalk solution. In addition, we have provided the ability to define a default set of credentials for all Service Bus endpoints sharing the same namespace so that these credentials can be reused. For sake of brevity, the full implementation of this class is not listed here, instead it is included into the sample code provided with this article.

For those developers who are familiar with the Enterprise Library’s Configuration Application Block, it is worth mentioning that the above custom configuration section is XML serializable and the following example depicts the XML view on configuration data stored in the section:

<ServiceBusConfiguration defaultEndpoint="GenericRequestOnRamp" defaultIssuerName="owner" defaultIssuerSecret="[some secret">
  <Endpoints>
    <add name="DiagnosticLoggingService" serviceNamespace="ns1" servicePath="IDiagnosticLoggingService" relayMode="Eventing" />    
<add name="GenericRequestResponseOnRamp" serviceNamespace="ns1" servicePath="GenericRequestResponseOnRamp" relayMode="Relayed" /> <add name="GenericRequestOnRamp" serviceNamespace="ns1" servicePath="GenericRequestOnRamp" relayMode="Relayed" /> <add name="PersistenceService" serviceNamespace="ns2" servicePath="IPersistenceService" issuerName="owner" issuerSecret="[some different secret]" relayMode="Relayed" /> <add name="InterRoleCommunication" serviceNamespace="ns1" servicePath="IInterRoleCommunicationService" relayMode="Eventing" /> </Endpoints> </ServiceBusConfiguration>

The second step was to implement a custom configuration source in which the above data can be centrally stored and easily maintained. Having reviewed a few options, we have decided to leverage the BizTalk’s Business Rules Engine as a first-class facility for authoring, versioning and managing the application configuration settings as these were just ordinary rules. The implementation of the Rules Engine Configuration Source for Enterprise Library is also included into accompanying sample code.

The Rules Engine has enabled us to offer a simple, easy-to-use user interface to the underlying application configuration which we further simplified by introducing a subset of the domain-specific terminology related to the configuration artifacts. In order to do that, we have taken the advantage of the custom vocabularies in BRE. The end result was that provisioning of the configuration settings to a target application has been abstracted through a set of friendly expressions such as in the following example (note the custom vocabulary terms used in the THEN section):

In order to restrict access to the Service Bus shared secret credentials and protect these from intrusive eyes of anyone who is not given the privilege of modifying or even seeing them, we have decided to take dependency on the Enterprise SSO configuration store. The SSO APIs provide a reliable and secure facility for storing configuration information in its encrypted form and enable restricting access to the sensitive information down to an individual Windows security group level.

Using the SSO Configuration Application MMC snap-in, we created several SSO affiliate applications, each corresponding to the type of configuration data persisted in the configuration store. We then defined the configuration settings that need to be securely stored in the SSO database, these were specified in a form of a name/value pair:

Using the Enterprise SSO MMC snap-in (SSO Administration tool), we restricted access to the new SSO application to specific Windows security groups. We also ensured that service accounts under which BizTalk host instances are configured to run are members of the security group which was granted the read-only access permissions.

We then instructed the BRE rule to fetch the shared secret credentials from the corresponding SSO application. We created a custom term in the BRE vocabulary which was found to have been a very intuitive for the application administrators:

In the last step, we told the SelfConfigurableServiceBusEndpointBehaviorElement implementation to retrieve the Service Bus endpoint information from the Rules Engine Configuration Store. To that end, the serviceBusEndpointName property is simply being used as a lookup key in the collection of named endpoint definitions.

In summary, the above implementation has demonstrated how a combination of products and technologies can be successfully brought together in order to:

  • Eliminate the need for storing the AppFabric Service Bus credentials in each individual BizTalk Receive Location and Send Port;
  • Centralize the collection of Service Bus endpoints along with their credentials in an easy-to-use UI and store these in the encrypted data store;
  • Leverage the WCF extensibility to query the Service Bus endpoint configuration and dynamically apply the transport credentials at runtime;
  • Restrict access to the Service Bus credentials to ensure that these cannot be retrieved or modified by anyone who were not granted the appropriate permissions.

Overall, the end result was that we increased the level of compliance with secure enterprise infrastructures as well as made it simpler to define and maintain the shared configuration data in a distributed application environment.

Conclusion

This article was pulled together with a simple intent, that is to demonstrate a collective power of WCF custom endpoint behaviors, Enterprise SSO configuration store and Business Rules Engine when solving a real-world manageability- and security-related challenge in the interoperability story between BizTalk and AppFabric Service Bus.

We explained how different building blocks can be cemented together to simplify the configuration aspects of a BizTalk solution communicating with the Service Bus. We also talked about securing the sensitive configuration data and locking down access to the Service Bus shared secret credentials should such environmental or security compliance requirements be in effect.

By following the examples provided in this article, some common headaches and inefficiencies can be greatly minimized. In addition, this article may help establish a pattern that can be used for dynamically configuring the WCF service endpoints with other settings not necessary limited to the transport credentials.

The accompanying sample code is available for download from the MSDN Code Gallery.

Additional Resources/References

For more information on the related topic, please visit the following resources:

Debugging Tips with Visual Studio 2010

Debugging Tips with Visual Studio 2010

This is the twenty-sixth in a series of blog posts I’m doing on the VS 2010 and .NET 4 release.

Today’s blog post covers some useful debugging tips that you can use with Visual Studio.  My friend Scott Cate (who has blogged dozens of great VS tips and tricks here) recently highlighted these to me as good tips that most developers using Visual Studio don’t seem to know about (even though most have been in the product for awhile).  Hopefully this post will help you discover them if you aren’t already taking advantage of them.  They are all easy to learn, and can help save you a bunch of time.

Run to Cursor (Ctrl + F10)

Often I see people debugging applications by hitting a breakpoint early in their application, and then repeatedly using F10/F11 to step through their code until they reach the actual location they really want to investigate.  In some cases they are carefully observing each statement they step over along the way (in which case using F10/F11 makes sense).  Often, though, people are just trying to quickly advance to the line of code they really care about – in which case using F10/F11 isn’t the best way to do this.

Instead, you might want to take advantage of the “run to cursor” feature that the debugger supports.  Simply position your cursor on the line in your code that you want to run the application to, and then press the Ctrl + F10 keys together.  This will run the application to that line location and then break into the debugger – saving you from having to make multiple F10/F11 keystrokes to get there.  This works even if the line of code you want to run to is in a separate method or class from the one you are currently debugging.

Conditional Breakpoints

Another common thing we often see in usability studies are cases where developers set breakpoints, run the application, try out some input, hit a breakpoint, and manually check if some condition is true before deciding to investigate further.  If the scenario doesn’t match what they are after, they press F5 to continue the app, try out some other input, and repeat the process manually.

Visual Studio’s conditional breakpoint capability provides a much, much easier way to handle this. Conditional breakpoints allow you to break in the debugger only if some specific condition that you specify is met.  They help you avoid having to manually inspect/resume your application, and can make the whole debugging process a lot less manual and tedious.

How to Enable a Conditional Breakpoint

Setting up a conditional breakpoint is really easy.  Press F9 in your code to set a breakpoint on a particular line:

image

Then right-click on the breakpoint “red circle” on the left of the editor and select the “Condition” context menu:

image

This will bring up a dialog that allows you indicate that the breakpoint should only be hit if some condition is true.  For example, we could indicate that we only want to break in the debugger if the size of the local paginatedDinners list is less than 10 by writing the code expression below:

image

Now when I re-run the application and do a search, the debugger will only break if I perform a search that returns less than 10 dinners.  If there are more than 10 dinners then the breakpoint won’t be hit.

Hit Count Feature

Sometimes you only want to break on a condition the Nth time it is true.  For example: only break the 5th time less than 10 dinners is returned from a search.

You can enable this by right-clicking on a breakpoint and selecting the “Hit count” menu command.

image

This will bring up a dialog that allows you to indicate that the breakpoint will only be hit the Nth time a condition is met, or every N times it is met, or every time after N occurrences:

image

Machine/Thread/Process Filtering

You can also right-click on a breakpoint and select the “Filter..” menu command to indicate that a breakpoint should only be hit if it occurs on a specific machine, or in a specific process, or on a specific thread.

TracePoints – Custom Actions When Hitting a BreakPoint

A debugging feature that a lot of people don’t know about is the ability to use TracePoints.  A TracePoint is a breakpoint that has some custom action that triggers when the breakpoint is hit.  This feature is particularly useful when you want to observe behavior within your application without breaking into the debugger.

I’m going to use a simple Console application to demonstrate how we might be able to take advantage of TracePoints.  Below is a recursive implementation of the Fibonacci sequence:

image

In the application above, we are using Console.WriteLine() to output the final Fibonacci sequence value for a specific input.  What if we wanted to observe the Fibonacci recursive sequence in action along the way within the debugger – without actually pausing the execution of it?  TracePoints can help us easily do this.

Setting up a TracePoint

You can enable a TracePoint by using F9 to set a breakpoint on a line of code, and then right-click on the breakpoint and choose the “When Hit” context menu command:

image

This will bring up the following dialog – which allows you to specify what should happen when the breakpoint is hit:

image

Above we’ve specified that we want to print a trace message anytime the breakpoint condition is met.  Notice that we’ve specified that we want to output the value of the local variable “x” as part of the message.  Local variables can be referenced using the {variableName} syntax.  There are also built-in commands (like $CALLER, $CALLSTACK, $FUNCTION, etc) that can be used to output common values within your trace messages.

Above we’ve also checked the “continue execution” checkbox at the bottom – which indicates that we do not want the application to break in the debugger.  Instead it will continue running – with the only difference being that our custom trace message will be output each time the breakpoint condition is met. 

And now when we run the application, we’ll find that our custom trace messages automatically show up in the “output” window of Visual Studio – allowing us to follow the recursive behavior of the application:

image

You can alternatively wire-up a custom trace listener to your application – in which case the messages you print from your TracePoints will be piped to it instead of the VS output window.

TracePoints – Running a Custom Macro

In a talk I gave last week in London, someone in the audience asked whether it was possible to automatically output all of the local variables when a TracePoint was hit. 

This capability isn’t built-in to Visual Studio – but can be enabled by writing a custom Macro in Visual Studio, and then wiring up a TracePoint to call the Macro when it is hit.  To enable this, open up the Macros IDE within Visual Studio (Tools->Macros->Macros IDE menu command).  Then under the MyMacros node in the project explorer, select a module or create a new one (for example: add one named “UsefulThings”).  Then paste the following VB macro code into the module and save it:

    Sub DumpLocals()

        Dim outputWindow As EnvDTE.OutputWindow

        outputWindow = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput).Object

 

        Dim currentStackFrame As EnvDTE.StackFrame

        currentStackFrame = DTE.Debugger.CurrentStackFrame

 

        outputWindow.ActivePane.OutputString("*Dumping Local Variables*" + vbCrLf)

        For Each exp As EnvDTE.Expression In currentStackFrame.Locals

            outputWindow.ActivePane.OutputString(exp.Name + " = " + exp.Value.ToString() + vbCrLf)

        Next

    End Sub

The above macro code loops through the current stack frame and dumps all local variables to the output window.

Using our custom DumpLocals Custom Macro

We can then take advantage of our custom “DumpLocals” macro using the simple addition application below:

image

We’ll use F9 to set a breakpoint on the return statement within our “Add” method above.  We’ll then right-click on the breakpoint and select the “When hit” menu command:

image

This will bring up the following dialog.  Unlike before where we used the “Print a message” checkbox option and manually specified the variables we wanted to output, this time we’ll instead select the “Run a macro” checkbox and point to the custom UsefulThings.DumpLocals macro we created above:

image

We’ll keep the “continue execution” checkbox selected so that the program will continue running even when our TracePoints are hit.

Running the Application

And now when we press F5 and run the application, we’ll see the following output show up in the Visual Studio “output” window when our Add method is invoked.  Note how the macro is automatically listing the name and value of each local variable when the TracePoint is hit:

image

Summary

The Visual Studio debugger is incredibly rich.  I highly recommend setting aside some time to really learn all of its features.  The above tips and tricks are but a few of the many features it provides that most people are actually unaware of.

I’ve previously blogged about other VS 2010 Debugger Improvements (including DataTip pinning, Import/Export of Breakpoints, Preserving Last Value Variables, and more).  I’ll be doing more blog posts in the future about the new VS 2010 Intellitrace and Dump File Debugging support as well.  These provide a bunch of additional cool new capabilities that can make debugging applications (including ones in production) a lot easier and more powerful.

Also make sure to check out Scott Cate’s excellent Visual Studio 2010 Tips and Tricks series to learn more about how to best take advantage of Visual Studio.  He has an absolutely awesome set of free videos and blog posts.

Hope this helps,

Scott

P.S. In addition to blogging, I am also now using Twitter for quick updates and to share links. Follow me at: twitter.com/scottgu

BTARN ’Service Content’ Error in the RNDisAssembler Component

We came across the following error late last night which was a bit of a show-stopper. We were trying to load a custom PIP (specifically a PIDX OrderChange), but kept hitting this issue time and time again:
Event Type: Error
Event Source: BizTalk Accelerator for RosettaNet
Event Category: None
Event ID: 4096
Description:
Source module:
RNDisAssembler
Correlation information:
Description:
Receive pipeline rejected incoming message
due to the following RNIF exception:
UNP.SCON.VALERR […]

Configuring an ASP.NET Web Application to Use a Windows Server AppFabric Cache for Session State

Last week I spent some time setting up Windows Server AppFabric Cache in anticipation of additional tasks this week.  The first task is configuring an ASP.NET web application to use Windows Server AppFabric Caching for the Session State Provider.  This allows the web application to spread session objects across the entire cache cluster, resulting in […]

“Unplugged” online chat with me this Wednesday

I just got back from my trip to India and the UK last week – and will be returning to more regular blogging shortly. 

This Wednesday (August 18th) I’m going to be doing another online LIDNUG chat session.  The chat will be from 10:00am to 11:30am Pacific Time.  I do these chats a few times a year and they tend to be pretty good.  Attendees can submit any questions they want to me, and listen to me answer them live via LiveMeeting.  You can learn more about it here and join the chat and ask questions at the appropriate time with this link.

Hope to get a chance to chat with some of you there!

Scott

P.S. In addition to blogging, I am also now using Twitter for quick updates and to share links. Follow me at: twitter.com/scottgu