How to read the Distributed Transaction Coordinator settings from C#…

I wrote a nice helper utility class for reading the settings from the MSDTC in .NET.  My WCF service requires distributed transactions, so I want to make sure my server was able detect if it was on. If its not, I throw an error and shutdown.

So, here is the class for your pleasure.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32;
using System.Threading;

namespace SeekfordsNamespace
{
    /// <summary>
    /// Used to get the DTC settings on a machine
    /// </summary>
    internal static class DTCUtility
    {
        /// <summary>
        /// Reads the DTC settings.
        /// </summary>
        /// <returns></returns>
        public static DTCSettings ReadDTCSettings()
        {
            //Lets grab the DTC settings from the registry and then populate our entity
            try
            {
                //we work from the local machine key
                var localReg = Registry.LocalMachine;
                //set the root dtc key
                string rootKey = @"SoftwareMicrosoftMSDTC";
                string securityKey = rootKey +@"Security";
                var dtcReg = localReg.OpenSubKey(rootKey, false);
                var securityReg = localReg.OpenSubKey(securityKey, false);

                DTCSettings settings = new DTCSettings();
                try
                {
                    //is network dtc access even turned on at all
                    settings.NetworkDTCAccess = ((int)securityReg.GetValue("NetworkDtcAccess", 0)) == 1;
                    //default to false, then prove it is on.
                    settings.AllowInbound = false;
                    settings.AllowOutbound = false;
                    //check to see if network access is on at all and transactions allowed
                    if (settings.NetworkDTCAccess &&
                        (((int)securityReg.GetValue("NetworkDtcAccessTransactions", 0)) == 1))
                    {
                        //so we can talk to network, can we allow outbound?
                        if (settings.NetworkDTCAccess &&
                        (((int)securityReg.GetValue("NetworkDtcAccessOutbound", 0)) == 1))
                        {
                            settings.AllowOutbound = true;
                        }
                        //same as above, but inbound connections allowed
                        if (settings.NetworkDTCAccess &&
                        (((int)securityReg.GetValue("NetworkDtcAccessInbound", 0)) == 1))
                        {
                            settings.AllowInbound = true;
                        }
                    }
                    //grab authentication values
                    bool allowOnlySecureRPCCalls = (int)dtcReg.GetValue(@"AllowOnlySecureRpcCalls", 0) == 1;
                    bool fallbackToUnsecuredRPC = (int)dtcReg.GetValue(@"FallbackToUnsecureRPCIfNecessary", 0) == 1;
                    bool turnOffRpcSecurity = (int)dtcReg.GetValue(@"TurnOffRpcSecurity", 0) == 1;
                    //process the logic to determine which mode is active.
                    settings.MutualAuthenticationRequired = (allowOnlySecureRPCCalls && !fallbackToUnsecuredRPC && !turnOffRpcSecurity);
                    settings.IncomingCallerAuthenticationRequired = (!allowOnlySecureRPCCalls && fallbackToUnsecuredRPC && !turnOffRpcSecurity);
                    settings.NoAuthenticationRequired = (!allowOnlySecureRPCCalls && !fallbackToUnsecuredRPC && turnOffRpcSecurity);

                }
                finally
                {
                    try
                    {
                        //close but not a failure if there is an error
                        dtcReg.Close();
                        securityReg.Close();
                    }
                    catch { }
                }
                return settings  ;
            }
            catch
            {
                return null;
            }
        }

    }

    /// <summary>
    /// DTC Settings
    /// </summary>
    internal class DTCSettings
    {
        /// <summary>
        /// Determines whether DTC on the local computer is allowed to access the network.
        /// This setting must be enabled in combination with one of the other settings to
        /// enable network DTC transactions.
        /// </summary>
        /// <value><c>true</c> if [network DTC access]; otherwise, <c>false</c>.</value>
        public bool NetworkDTCAccess { get; set; }
        /// <summary>
        /// Allows a distributed transaction that originates from a remote computer to run on this computer.
        /// Default setting: Off
        /// </summary>
        /// <value><c>true</c> if [allow inbound]; otherwise, <c>false</c>.</value>
        public bool AllowInbound { get; set; }
        /// <summary>
        /// Allows the local computer to initiate a transaction and run it on a remote computer.
        /// </summary>
        /// <value><c>true</c> if [allow outbound]; otherwise, <c>false</c>.</value>
        public bool AllowOutbound { get; set; }
        /// <summary>
        /// Adds support for mutual authentication in future versions and is the highest secured
        /// communication mode. In the current versions of Windows and Windows Server, it is
        /// functionally equivalent to the Incoming Caller Authentication Required setting.
        /// This is the recommended transaction mode for clients running Windows XP SP2 and
        /// servers running a member of the Windows Server 2003 family.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if [mutual authentication required]; otherwise, <c>false</c>.
        /// </value>
        public bool MutualAuthenticationRequired { get; set; }
        /// <summary>
        /// Requires the local DTC to communicate with a remote DTC using only encrypted messages
        /// and mutual authentication. This setting is recommended for servers running Windows Server
        /// 2003 that are operating in a cluster.
        /// Only Windows Server 2003 and Windows XP SP2 support this feature, so you should only use
        /// this if you know that the DTC on the remote computer runs either the Windows Server 2003
        /// or Windows XP SP2 operating system.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if [incoming caller authentication required]; otherwise, <c>false</c>.
        /// </value>
        public bool IncomingCallerAuthenticationRequired { get; set; }
        /// <summary>
        /// Provides system compatibility between previous versions of the Windows operating system.
        /// When enabled, communication on the network between DTCs can fall back to a non-authentication
        /// or non-encrypted communication if a secure communication channel cannot be established.
        /// This setting should be used if the DTC on the remote computer runs a Windows 2000 operating system
        /// or a Windows XP operating system earlier than SP2. This setting is also useful when the DTCs
        /// that are involved are located on computers that are in domains that do not have an established
        /// trust relationship or if the computers are part of a Windows workgroup.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if [no authentication required]; otherwise, <c>false</c>.
        /// </value>
        public bool NoAuthenticationRequired { get; set; }

        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public override string ToString()
        {
            StringBuilder state = new StringBuilder();
            state.AppendFormat("NetworkDTCAccess: {0}rn", NetworkDTCAccess);
            state.AppendFormat("AllowInbound: {0}rn", AllowInbound);
            state.AppendFormat("AllowOutbound: {0}rn", AllowOutbound);
            state.AppendFormat("MutualAuthenticationRequired: {0}rn", MutualAuthenticationRequired);
            state.AppendFormat("IncomingCallerAuthenticationRequired: {0}rn", IncomingCallerAuthenticationRequired);
            state.AppendFormat("NoAuthenticationRequired: {0}rn", NoAuthenticationRequired);
            return state.ToString();
        }

    }

}

Happy coding!

0 Replies to “How to read the Distributed Transaction Coordinator settings from C#…”

Leave a Reply

Your email address will not be published. Required fields are marked *