DurableInstanceContextProvider.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx35 / System.WorkflowServices / System / ServiceModel / Dispatcher / DurableInstanceContextProvider.cs / 1305376 / DurableInstanceContextProvider.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{ 
    using System.Collections.Generic;
    using System.Runtime; 
    using System.Runtime.Diagnostics; 
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description; 
    using System.ServiceModel.Diagnostics;
    using System.Threading;
    using System.Diagnostics;
 
    abstract class DurableInstanceContextProvider : IInstanceContextProvider
    { 
        ContextCache contextCache; 

        bool isPerCall; 
        ServiceHostBase serviceHostBase;

        protected DurableInstanceContextProvider(ServiceHostBase serviceHostBase, bool isPerCall)
        { 
            if (serviceHostBase == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serviceHostBase"); 
            }
 
            this.serviceHostBase = serviceHostBase;

            if (serviceHostBase.Description.Behaviors.Find() == null)
            { 
                serviceHostBase.ServiceThrottle.MaxConcurrentInstances = (new ServiceThrottlingBehavior()).MaxConcurrentInstances;
            } 
            this.contextCache = new ContextCache(); 
            this.isPerCall = isPerCall;
        } 

        protected ContextCache Cache
        {
            get 
            {
                return this.contextCache; 
            } 
        }
 
        public virtual InstanceContext GetExistingInstanceContext(Message message, IContextChannel channel)
        {
            if (message == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
            } 
            if (channel == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("channel"); 
            }

            Guid instanceId = GetInstanceIdFromMessage(message);
            InstanceContext result = null; 

            if (instanceId != Guid.Empty) //Not an activation request. 
            { 
                if (contextCache.TryGetInstanceContext(instanceId, out result))
                { 
                    lock (result.ThisLock)
                    {
                        if (!string.IsNullOrEmpty(channel.SessionId) && !result.IncomingChannels.Contains(channel))
                        { 
                            result.IncomingChannels.Add(channel);
                        } 
                    } 
                    return result;
                } 
            }
            return result;
        }
 
        public int GetReferenceCount(Guid instanceId)
        { 
            return this.Cache.GetReferenceCount(instanceId); 
        }
 
        public virtual void InitializeInstanceContext(InstanceContext instanceContext, Message message, IContextChannel channel)
        {
            if (instanceContext == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("instanceContext");
            } 
            if (message == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message"); 
            }
            if (channel == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("channel"); 
            }
 
            Guid instanceId = GetInstanceIdFromMessage(message); 
            DurableInstance durableInstance;
            if (instanceId == Guid.Empty) //Activation Request. 
            {
                instanceId = Guid.NewGuid();
                durableInstance = this.OnCreateNewInstance(instanceId);
                message.Properties[DurableMessageDispatchInspector.NewDurableInstanceIdPropertyName] = instanceId; 
            }
            else 
            { 
                durableInstance = this.OnGetExistingInstance(instanceId);
            } 

            Fx.Assert(durableInstance != null, "Durable instance should never be null at this point.");
            durableInstance.Open();
 
            instanceContext.Extensions.Add(durableInstance);
 
            if (!string.IsNullOrEmpty(channel.SessionId)) 
            {
                instanceContext.IncomingChannels.Add(channel); 
            }

            contextCache.AddInstanceContext(instanceId, instanceContext);
 
            if (DiagnosticUtility.ShouldTraceInformation)
            { 
                string traceText = SR.GetString(SR.TraceCodeDICPInstanceContextCached, instanceId); 
                TraceUtility.TraceEvent(TraceEventType.Information,
                    TraceCode.DICPInstanceContextCached, SR.GetString(SR.TraceCodeDICPInstanceContextCached), 
                    new StringTraceRecord("InstanceDetail", traceText),
                    this, null);
            }
        } 

        public virtual bool IsIdle(InstanceContext instanceContext) 
        { 
            bool removed = false;
 
            if (instanceContext == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("instanceContext");
            } 

            DurableInstance durableInstance = instanceContext.Extensions.Find(); 
 
            if (durableInstance == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new InvalidOperationException(
                    SR2.GetString(
                    SR2.RequiredInstanceContextExtensionNotFound, 
                    typeof(DurableInstance).Name)));
            } 
 
            lock (instanceContext.ThisLock)
            { 
                if (instanceContext.IncomingChannels.Count == 0)
                {
                    removed = contextCache.RemoveIfNotBusy(durableInstance.InstanceId, instanceContext);
                } 
            }
 
            if (removed && DiagnosticUtility.ShouldTraceInformation) 
            {
                string traceText = SR.GetString(SR.TraceCodeDICPInstanceContextRemovedFromCache, durableInstance.InstanceId); 
                TraceUtility.TraceEvent(TraceEventType.Information,
                    TraceCode.DICPInstanceContextRemovedFromCache, SR.GetString(SR.TraceCodeDICPInstanceContextRemovedFromCache),
                    new StringTraceRecord("InstanceDetail", traceText),
                    this, null); 
            }
            return removed; 
        } 

        public virtual void NotifyIdle(InstanceContextIdleCallback callback, InstanceContext instanceContext) 
        {

        }
 
        //Called by MessageInspector.BeforeReply
        internal void DecrementActivityCount(Guid instanceId) 
        { 
            contextCache.ReleaseReference(instanceId);
        } 

        internal void UnbindAbortedInstance(InstanceContext instanceContext, Guid instanceId)
        {
            if (instanceContext == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("instanceContext"); 
            } 

            //We made our best effor to clean up the instancecontext out of our cache. 
            //If another request already in middle of processing the request on InstanceContext
            //It will Fail with CommunicationException.
            this.contextCache.Remove(instanceId, instanceContext);
        } 

        protected virtual Guid GetInstanceIdFromMessage(Message message) 
        { 
            if (!this.isPerCall)
            { 
                ContextMessageProperty contextProperties = null;
                string instanceId = null;

                if (ContextMessageProperty.TryGet(message, out contextProperties)) 
                {
                    if (contextProperties.Context.TryGetValue(WellKnownContextProperties.InstanceId, out instanceId)) 
                    { 
                        return Fx.CreateGuid(instanceId);
                    } 
                }
            }
            return Guid.Empty;
        } 

        protected abstract DurableInstance OnCreateNewInstance(Guid instanceId); 
        protected abstract DurableInstance OnGetExistingInstance(Guid instanceId); 

        //This class takes self contained lock, never calls out with lock taken. 
        protected class ContextCache
        {
            Dictionary contextCache;
            object lockObject = new object(); 

            public ContextCache() 
            { 
                contextCache = new Dictionary();
            } 

            public void AddInstanceContext(Guid instanceId, InstanceContext instanceContext)
            {
                ContextItem contextItem; 
                int? referenceCount = null;
 
                lock (lockObject) 
                {
                    if (!contextCache.TryGetValue(instanceId, out contextItem)) 
                    {
                        //This will be the case for activation request.
                        contextItem = new ContextItem(instanceId);
                        referenceCount = contextItem.AddReference(); 
                        contextCache.Add(instanceId, contextItem);
                    } 
                } 
                contextItem.InstanceContext = instanceContext;
 
                if (DiagnosticUtility.ShouldTraceInformation && referenceCount.HasValue)
                {
                    string traceText = SR2.GetString(SR2.DurableInstanceRefCountToInstanceContext, instanceId, referenceCount.Value);
                    TraceUtility.TraceEvent(TraceEventType.Information, 
                        TraceCode.InstanceContextBoundToDurableInstance, SR.GetString(SR.TraceCodeInstanceContextBoundToDurableInstance),
                        new StringTraceRecord("InstanceDetail", traceText), 
                        this, null); 
                }
            } 

            public bool Contains(Guid instanceId, InstanceContext instanceContext)
            {
                ContextItem contextItem = null; 

                lock (this.lockObject) 
                { 
                    if (contextCache.TryGetValue(instanceId, out contextItem))
                    { 
                        return object.ReferenceEquals(contextItem.InstanceContext, instanceContext);
                    }
                    return false;
                } 
            }
 
            public int GetReferenceCount(Guid instanceId) 
            {
                int result = 0; 

                lock (lockObject)
                {
                    ContextItem contextItem; 
                    if (contextCache.TryGetValue(instanceId, out contextItem))
                    { 
                        result = contextItem.ReferenceCount; 
                    }
                } 

                return result;
            }
 
            public void ReleaseReference(Guid instanceId)
            { 
                int referenceCount = -1; 
                ContextItem contextItem;
 
                lock (lockObject)
                {
                    if (contextCache.TryGetValue(instanceId, out contextItem))
                    { 
                        referenceCount = contextItem.ReleaseReference();
                    } 
                    else 
                    {
                        Fx.Assert(false, "Cannot Release Reference of non exisiting items"); 
                    }
                }

                if (DiagnosticUtility.ShouldTraceInformation) 
                {
                    string traceText = SR2.GetString(SR2.DurableInstanceRefCountToInstanceContext, instanceId, referenceCount); 
                    TraceUtility.TraceEvent(TraceEventType.Information, 
                        TraceCode.InstanceContextDetachedFromDurableInstance, SR.GetString(SR.TraceCodeInstanceContextDetachedFromDurableInstance),
                        new StringTraceRecord("InstanceDetail", traceText), 
                        this, null);
                }
            }
 
            public bool Remove(Guid instanceId, InstanceContext instanceContext)
            { 
                lock (this.lockObject) 
                {
                    ContextItem contextItem = null; 
                    if (this.contextCache.TryGetValue(instanceId, out contextItem))
                    {
                        if (object.ReferenceEquals(instanceContext, contextItem.InstanceContext))
                        { 
                            return this.contextCache.Remove(instanceId);
                        } 
                    } 
                    //InstanceContext is not in memory.
                    return false; 
                }
            }

            public bool RemoveIfNotBusy(Guid instanceId, InstanceContext instanceContext) 
            {
                lock (lockObject) 
                { 
                    ContextItem contextItem = null;
                    if (contextCache.TryGetValue(instanceId, out contextItem)) 
                    {
                        if (object.ReferenceEquals(contextItem.InstanceContext, instanceContext))
                        {
                            return (!contextItem.HasOutstandingReference) 
                                && (contextCache.Remove(instanceId));
                        } 
                    } 
                    //InstanceContext is not in memory.
                    return true; 
                }
            }

            //Helper method to call from GetExistingInstanceContext 
            //returns true  : If InstanceContext is found in cache & guaranteed to stay in cache until ReleaseReference is called.
            //returns false : If InstanceContext is not found in cache; 
            //               reference & slot is created for the ID; 
            //               InitializeInstanceContext to call AddInstanceContext.
            public bool TryGetInstanceContext(Guid instanceId, out InstanceContext instanceContext) 
            {
                ContextItem contextItem;
                instanceContext = null;
                int referenceCount = -1; 

                try 
                { 
                    lock (lockObject)
                    { 
                        if (!contextCache.TryGetValue(instanceId, out contextItem))
                        {
                            contextItem = new ContextItem(instanceId);
                            referenceCount = contextItem.AddReference(); 
                            contextCache.Add(instanceId, contextItem);
                            return false; 
                        } 
                        referenceCount = contextItem.AddReference();
                    } 
                }
                finally
                {
                    if (DiagnosticUtility.ShouldTraceInformation) 
                    {
                        string traceText = SR2.GetString(SR2.DurableInstanceRefCountToInstanceContext, instanceId, referenceCount); 
                        TraceUtility.TraceEvent(TraceEventType.Information, 
                            TraceCode.InstanceContextBoundToDurableInstance, SR.GetString(SR.TraceCodeInstanceContextBoundToDurableInstance),
                            new StringTraceRecord("InstanceDetail", traceText), 
                            this, null);
                    }
                }
                instanceContext = contextItem.InstanceContext; 
                return true;
            } 
 

            class ContextItem 
            {
                InstanceContext context;
                Guid instanceId;
                object lockObject; 
                int referenceCount;
 
                public ContextItem(Guid instanceId) 
                {
                    lockObject = new object(); 
                    referenceCount = 0;
                    this.instanceId = instanceId;
                }
 
                public bool HasOutstandingReference
                { 
                    get 
                    {
                        return this.referenceCount > 0; 
                    }
                }

                public InstanceContext InstanceContext 
                {
                    get 
                    { 
                        if (this.context == null)
                        { 
                            lock (this.lockObject)
                            {
                                if (this.context == null)
                                { 
                                    Monitor.Wait(this.lockObject);
                                } 
                            } 
                        }
                        Fx.Assert(this.context != null, "Context cannot be null at this point"); 
                        return this.context;
                    }
                    set
                    { 
                        if (value == null)
                        { 
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value"); 
                        }
                        this.context = value; 
                        lock (this.lockObject)
                        {
                            Monitor.PulseAll(this.lockObject);
                        } 
                    }
                } 
 
                public int ReferenceCount
                { 
                    get
                    {
                        return this.referenceCount;
                    } 
                }
 
                public int AddReference() 
                {
                    //Called from higher locks taken 
                    return ++this.referenceCount;
                }

                public int ReleaseReference() 
                {
                    Fx.Assert(referenceCount > 0, "Reference count gone to negative"); 
                    //Called from higher locks taken 
                    return --this.referenceCount;
                } 
            }
        }
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK