Bus.Send - ObjectDisposedException "Safe handle has been closed" within WindowsIdentityEnricher

564 views
Skip to first unread message

David Ketnor

unread,
Mar 18, 2014, 2:03:05 PM3/18/14
to particula...@googlegroups.com

We are encountering an issue when sending messages to the bus within a Web application (Asp.net, MVC, SignalR). Whenever we make a call to the Bus.Send we encounter the above exception. I believe it might be related to the use of Thread.CurrentPrincipal.Identity.Name within the WindowsIdentityEnricher class.

namespace NServiceBus.Impersonation.Windows
{
    using System.Threading;
    using MessageMutator;
 
    /// <summary>
    /// Stamps outgoing messages with the current windows identity
    /// </summary>
    public class WindowsIdentityEnricher : IMutateOutgoingTransportMessages
    {
        void IMutateOutgoingTransportMessages.MutateOutgoing(object[] messages, TransportMessage transportMessage)
        {
            transportMessage.Headers[Headers.WindowsIdentityName] = Thread.CurrentPrincipal.Identity.Name;
        }
    }
}

 

It appears to be linked to an issue identified here, in which the identity of the user is bound to each request and the Thread.CurrentPrincipal is null.

http://forums.iis.net/t/1177028.aspx?IIS7+in+integrated+mode+throws+an+ObjectDisposedException+when+trying+to+access+the+WindowsIdentity


My questions are:

12.     Is this IIS closing the identity between the requests? Should the above code in the WindowsIdentityEnricher be wrapped within an exception? 

2.       Are there any methods can disable certain message mutators? Is the windows identity a requirement for messages or is it merely used for logging purposes? 

3.       Given my implementation below. Is it a safe implementation? Are there any obvious gotchas? (reduced for clarity)

 
        private static IBus bus;
        protected static IBus Bus
        {
            get
            {
                if (bus == null)
                {
                    Init(Endpoint);
                }
                    
                return bus;
            }
        }

         CALLED WITHIN Globala.asax Application Start
         public static void Init()
         {
            if (bus != null)
                 return;
 
            lock (typeof(ServiceBus))
             {
                if (bus != null)
                     return;
 
                 bus = Configure.With()
                    .DefineEndpointName(EndpointName)
                    .DoNotCreateQueues()
                    .StructureMapBuilder()
                    .UseTransport<SqlServer>(ConnectionStringName)
                    .PurgeOnStartup(false)
                    .UnicastBus()
                     .CreateBus()
                     .Start(() => Configure.Instance.ForInstallationOn<Windows>().Install());
                  }
         }
 
        public static void SendMessage(Command cmd)
        {            
                 Send(cmd);
        }
 
        private static void Send(object cmd)
        {
            try
            {
                Bus.Send(cmd); EXCEPTION OCCURS HERE
            }
            catch (Exception e)
            {
                // exception handling here
            }
        }
  }


Product name: 

NServiceBus

Version:

4.4.0

Exception:

ObjectDisposedException

Message:

Safe handle has been closed

Stacktrace:

   at System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean& success)     at System.StubHelpers.StubHelpers.SafeHandleAddRef(SafeHandle pHandle, Boolean& success)     at Microsoft.Win32.Win32Native.GetTokenInformation(SafeTokenHandle TokenHandle, UInt32 TokenInformationClass, SafeLocalAllocHandle TokenInformation, UInt32 TokenInformationLength, UInt32& ReturnLength)     at System.Security.Principal.WindowsIdentity.GetTokenInformation(SafeTokenHandle tokenHandle, TokenInformationClass tokenInformationClass)     at System.Security.Principal.WindowsIdentity.get_User()     at System.Security.Principal.WindowsIdentity.GetName()     at System.Security.Principal.WindowsIdentity.get_Name()     at NServiceBus.Impersonation.Windows.WindowsIdentityEnricher.NServiceBus.MessageMutator.IMutateOutgoingTransportMessages.MutateOutgoing(Object[] messages, TransportMessage transportMessage) in \src\NServiceBus.Core\Impersonation\Windows\WindowsIdentityEnricher.cs:line 13     at NServiceBus.MessageMutator.MutateOutgoingPhysicalMessageBehavior.Invoke(SendPhysicalMessageContext context, Action next) in \src\NServiceBus.Core\MessageMutator\MutateOutgoingPhysicalMessageBehavior.cs:line 20     at NServiceBus.Pipeline.BehaviorChain`1.InvokeNext(T context) in \src\NServiceBus.Core\Pipeline\BehaviorChain.cs:line 38     at NServiceBus.Pipeline.BehaviorChain`1.<>c__DisplayClass1.<InvokeNext>b__0() in \src\NServiceBus.Core\Pipeline\BehaviorChain.cs:line 38     at NServiceBus.Unicast.Behaviors.SerializeMessagesBehavior.Invoke(SendPhysicalMessageContext context, Action next) in \src\NServiceBus.Core\Unicast\Behaviors\SerializeMessagesBehavior.cs:line 43     at NServiceBus.Pipeline.BehaviorChain`1.InvokeNext(T context) in \src\NServiceBus.Core\Pipeline\BehaviorChain.cs:line 38     at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context) in \src\NServiceBus.Core\Pipeline\PipelineExecutor.cs:line 137     at NServiceBus.Pipeline.PipelineExecutor.InvokeSendPipeline(SendOptions sendOptions, TransportMessage physicalMessage) in \src\NServiceBus.Core\Pipeline\PipelineExecutor.cs:line 101     at NServiceBus.Unicast.Behaviors.CreatePhysicalMessageBehavior.Invoke(SendLogicalMessagesContext context, Action next) in \src\NServiceBus.Core\Unicast\Behaviors\CreatePhysicalMessageBehavior.cs:line 53     at NServiceBus.Pipeline.BehaviorChain`1.InvokeNext(T context) in \src\NServiceBus.Core\Pipeline\BehaviorChain.cs:line 38     at NServiceBus.Pipeline.BehaviorChain`1.<>c__DisplayClass1.<InvokeNext>b__0() in \src\NServiceBus.Core\Pipeline\BehaviorChain.cs:line 38     at NServiceBus.Unicast.Behaviors.MultiMessageBehavior.Invoke(SendLogicalMessagesContext context, Action next) in\src\NServiceBus.Core\Unicast\Behaviors\MultiMessageBehavior.cs:line 21     at NServiceBus.Pipeline.BehaviorChain`1.InvokeNext(T context) in \src\NServiceBus.Core\Pipeline\BehaviorChain.cs:line 38     at NServiceBus.Pipeline.BehaviorChain`1.<>c__DisplayClass1.<InvokeNext>b__0() in \src\NServiceBus.Core\Pipeline\BehaviorChain.cs:line 38     at NServiceBus.Unicast.Behaviors.MultiSendValidatorBehavior.Invoke(SendLogicalMessagesContext context, Action next) in \src\NServiceBus.Core\Unicast\Behaviors\MultiSendValidatorBehavior.cs:line 36     at NServiceBus.Pipeline.BehaviorChain`1.InvokeNext(T context) in \src\NServiceBus.Core\Pipeline\BehaviorChain.cs:line 38     at NServiceBus.Pipeline.PipelineExecutor.Execute[T](BehaviorChain`1 pipelineAction, T context) in \src\NServiceBus.Core\Pipeline\PipelineExecutor.cs:line 137     at NServiceBus.Pipeline.PipelineExecutor.InvokeSendPipeline(SendOptions sendOptions, IEnumerable`1 messages) in \src\NServiceBus.Core\Pipeline\PipelineExecutor.cs:line 79     at NServiceBus.Unicast.UnicastBus.InvokeSendPipeline(SendOptions sendOptions, List`1 messages) in \src\NServiceBus.Core\Unicast\UnicastBus.cs:line 744     at NServiceBus.Unicast.UnicastBus.SendMessages(SendOptions sendOptions, List`1 messages) in \src\NServiceBus.Core\Unicast\UnicastBus.cs:line 725     at NServiceBus.Unicast.UnicastBus.Send(Object[] messages) in \src\NServiceBus.Core\Unicast\UnicastBus.cs:line 571     at NServiceBus.Unicast.UnicastBus.Send(Object message) in \src\NServiceBus.Core\Unicast\UnicastBus.cs:line 555     at XXXXXX.Send(Object cmd)

Things I've tried:

I have tried overriding the DependencyLifecycle to InstancePerCall for the WindowsIdentityEnricher but to no avail.

I have experimented with the ImpersonateSender method when instantiating the Bus as well.

Considerations:

  • Using StructureMap builder
  • Using SqlServer transport
  • Occurring sporadically within ASP.net and MVC
  • Occurring frequently within SignalR
  • IIS7 Integrated Mode

I thought I'd created a forum post already but I can't seem to find it... so apologies if this creates a double post.

Thanks

David Ketnor

unread,
Mar 19, 2014, 6:35:04 AM3/19/14
to particula...@googlegroups.com
I have found changing the implementation of the WindowsIdentityEnricher class to the following resolves the issue. I haven't tested this in other additional hosting methods I.e. Self Hosting. I'm not sure what would happen in the instance of the identity not being retrievable and what ramifications it would on messages. Also, any performance considerations for calling WindowsIdentity.GetCurrent(); on each message dispatch.

    /// <summary>
    /// Stamps outgoing messages with the current windows identity
    /// </summary>
    public class WindowsIdentityEnricher : IMutateOutgoingTransportMessages
    {
        void IMutateOutgoingTransportMessages.MutateOutgoing(object[] messages, TransportMessage
 transportMessage)
        {
            transportMessage.Headers[Headers.WindowsIdentityName] = GetWindowsIdentityName();
        }
 
        private string GetWindowsIdentityName()
        {
            var identityName = string.Empty;
 
            var currentIdentity = WindowsIdentity.GetCurrent();
 
            if (currentIdentity != null)
            {
                identityName = currentIdentity.Name;
            }
 
            return identityName;
        }
    }

I'm still open this issue being down to my implementation, so any pointers on that would be appreciated.

Thanks

Simon Cropp

unread,
Mar 24, 2014, 11:13:59 PM3/24/14
to particula...@googlegroups.com
Message has been deleted

David Ketnor

unread,
Mar 25, 2014, 7:44:32 AM3/25/14
to particula...@googlegroups.com
Thank you... The following Sample will allow you to recreate this issue.
Reply all
Reply to author
Forward
0 new messages