| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672 |
- //-----------------------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //-----------------------------------------------------------------------------
- namespace System.ServiceModel
- {
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Runtime;
- using System.Runtime.CompilerServices;
- using System.ServiceModel.Channels;
- using System.ServiceModel.Diagnostics;
- using System.ServiceModel.Dispatcher;
- using System.Threading;
- using System.ServiceModel.Diagnostics.Application;
- public sealed class InstanceContext : CommunicationObject, IExtensibleObject<InstanceContext>
- {
- internal static InstanceContextEmptyCallback NotifyEmptyCallback = new InstanceContextEmptyCallback(InstanceContext.NotifyEmpty);
- internal static InstanceContextIdleCallback NotifyIdleCallback = new InstanceContextIdleCallback(InstanceContext.NotifyIdle);
- bool autoClose;
- InstanceBehavior behavior;
- ServiceChannelManager channels;
- ConcurrencyInstanceContextFacet concurrency;
- ExtensionCollection<InstanceContext> extensions;
- readonly ServiceHostBase host;
- QuotaThrottle quotaThrottle;
- ServiceThrottle serviceThrottle;
- int instanceContextManagerIndex;
- object serviceInstanceLock = new object();
- SynchronizationContext synchronizationContext;
- TransactionInstanceContextFacet transaction;
- object userObject;
- bool wellKnown;
- SynchronizedCollection<IChannel> wmiChannels;
- bool isUserCreated;
- public InstanceContext(object implementation)
- : this(null, implementation)
- {
- }
- public InstanceContext(ServiceHostBase host, object implementation)
- : this(host, implementation, true)
- {
- }
- internal InstanceContext(ServiceHostBase host, object implementation, bool isUserCreated)
- : this(host, implementation, true, isUserCreated)
- {
- }
- internal InstanceContext(ServiceHostBase host, object implementation, bool wellKnown, bool isUserCreated)
- {
- this.host = host;
- if (implementation != null)
- {
- this.userObject = implementation;
- this.wellKnown = wellKnown;
- }
- this.autoClose = false;
- this.channels = new ServiceChannelManager(this);
- this.isUserCreated = isUserCreated;
- }
- public InstanceContext(ServiceHostBase host)
- : this(host, true)
- {
- }
- internal InstanceContext(ServiceHostBase host, bool isUserCreated)
- {
- if (host == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("host"));
- }
- this.host = host;
- this.autoClose = true;
- this.channels = new ServiceChannelManager(this, NotifyEmptyCallback);
- this.isUserCreated = isUserCreated;
- }
- internal bool IsUserCreated
- {
- get { return this.isUserCreated; }
- set { this.isUserCreated = value; }
- }
- internal bool IsWellKnown
- {
- get { return this.wellKnown; }
- }
- internal bool AutoClose
- {
- get { return this.autoClose; }
- set { this.autoClose = value; }
- }
- internal InstanceBehavior Behavior
- {
- get { return this.behavior; }
- set
- {
- if (this.behavior == null)
- {
- this.behavior = value;
- }
- }
- }
- internal ConcurrencyInstanceContextFacet Concurrency
- {
- get
- {
- if (this.concurrency == null)
- {
- lock (this.ThisLock)
- {
- if (this.concurrency == null)
- this.concurrency = new ConcurrencyInstanceContextFacet();
- }
- }
- return this.concurrency;
- }
- }
- internal static InstanceContext Current
- {
- get { return OperationContext.Current != null ? OperationContext.Current.InstanceContext : null; }
- }
- protected override TimeSpan DefaultCloseTimeout
- {
- get
- {
- if (this.host != null)
- {
- return this.host.CloseTimeout;
- }
- else
- {
- return ServiceDefaults.CloseTimeout;
- }
- }
- }
- protected override TimeSpan DefaultOpenTimeout
- {
- get
- {
- if (this.host != null)
- {
- return this.host.OpenTimeout;
- }
- else
- {
- return ServiceDefaults.OpenTimeout;
- }
- }
- }
- public IExtensionCollection<InstanceContext> Extensions
- {
- get
- {
- this.ThrowIfClosed();
- lock (this.ThisLock)
- {
- if (this.extensions == null)
- this.extensions = new ExtensionCollection<InstanceContext>(this, this.ThisLock);
- return this.extensions;
- }
- }
- }
- internal bool HasTransaction
- {
- get { return (this.transaction != null) && !object.Equals(this.transaction.Attached, null); }
- }
- public ICollection<IChannel> IncomingChannels
- {
- get
- {
- this.ThrowIfClosed();
- return channels.IncomingChannels;
- }
- }
- bool IsBusy
- {
- get
- {
- if (this.State == CommunicationState.Closed)
- return false;
- return this.channels.IsBusy;
- }
- }
- bool IsSingleton
- {
- get
- {
- return ((this.behavior != null) &&
- InstanceContextProviderBase.IsProviderSingleton(this.behavior.InstanceContextProvider));
- }
- }
- public ICollection<IChannel> OutgoingChannels
- {
- get
- {
- this.ThrowIfClosed();
- return channels.OutgoingChannels;
- }
- }
- public ServiceHostBase Host
- {
- get
- {
- this.ThrowIfClosed();
- return this.host;
- }
- }
- public int ManualFlowControlLimit
- {
- get { return this.EnsureQuotaThrottle().Limit; }
- set { this.EnsureQuotaThrottle().SetLimit(value); }
- }
- internal QuotaThrottle QuotaThrottle
- {
- get { return this.quotaThrottle; }
- }
- internal ServiceThrottle ServiceThrottle
- {
- get { return this.serviceThrottle; }
- set
- {
- this.ThrowIfDisposed();
- this.serviceThrottle = value;
- }
- }
- internal int InstanceContextManagerIndex
- {
- get { return this.instanceContextManagerIndex; }
- set { this.instanceContextManagerIndex = value; }
- }
- public SynchronizationContext SynchronizationContext
- {
- get { return this.synchronizationContext; }
- set
- {
- this.ThrowIfClosedOrOpened();
- this.synchronizationContext = value;
- }
- }
- new internal object ThisLock
- {
- get { return base.ThisLock; }
- }
- internal TransactionInstanceContextFacet Transaction
- {
- get
- {
- if (this.transaction == null)
- {
- lock (this.ThisLock)
- {
- if (this.transaction == null)
- this.transaction = new TransactionInstanceContextFacet(this);
- }
- }
- return this.transaction;
- }
- }
- internal object UserObject
- {
- get { return this.userObject; }
- }
- internal ICollection<IChannel> WmiChannels
- {
- get
- {
- if (this.wmiChannels == null)
- {
- lock (this.ThisLock)
- {
- if (this.wmiChannels == null)
- {
- this.wmiChannels = new SynchronizedCollection<IChannel>();
- }
- }
- }
- return this.wmiChannels;
- }
- }
- protected override void OnAbort()
- {
- channels.Abort();
- this.Unload();
- }
- internal IAsyncResult BeginCloseInput(TimeSpan timeout, AsyncCallback callback, object state)
- {
- return channels.BeginCloseInput(timeout, callback, state);
- }
- internal void BindRpc(ref MessageRpc rpc)
- {
- this.ThrowIfClosed();
- this.channels.IncrementActivityCount();
- rpc.SuccessfullyBoundInstance = true;
- }
- internal void BindIncomingChannel(ServiceChannel channel)
- {
- this.ThrowIfDisposed();
- channel.InstanceContext = this;
- IChannel proxy = (IChannel)channel.Proxy;
- this.channels.AddIncomingChannel(proxy);
- // CSDMain 265783: Memory Leak on Chat Stress test scenario
- // There's a race condition while on one thread we received a new request from underlying sessionful channel
- // and on another thread we just aborted the channel. So the channel will be added to the IncomingChannels list of
- // ServiceChannelManager and never get a chance to be removed.
- if (proxy != null)
- {
- CommunicationState state = channel.State;
- if (state == CommunicationState.Closing
- || state == CommunicationState.Closed
- || state == CommunicationState.Faulted)
- {
- this.channels.RemoveChannel(proxy);
- }
- }
- }
- void CloseIfNotBusy()
- {
- if (!(this.State != CommunicationState.Created && this.State != CommunicationState.Opening))
- {
- Fx.Assert("InstanceContext.CloseIfNotBusy: (this.State != CommunicationState.Created && this.State != CommunicationState.Opening)");
- }
- if (this.State != CommunicationState.Opened)
- return;
- if (this.IsBusy)
- return;
- if (this.behavior.CanUnload(this) == false)
- return;
- try
- {
- if (this.State == CommunicationState.Opened)
- this.Close();
- }
- catch (ObjectDisposedException e)
- {
- DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
- }
- catch (InvalidOperationException e)
- {
- DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
- }
- catch (CommunicationException e)
- {
- DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
- }
- catch (TimeoutException e)
- {
- if (TD.CloseTimeoutIsEnabled())
- {
- TD.CloseTimeout(e.Message);
- }
- DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
- }
- }
- internal void CloseInput(TimeSpan timeout)
- {
- channels.CloseInput(timeout);
- }
- internal void EndCloseInput(IAsyncResult result)
- {
- channels.EndCloseInput(result);
- }
- [MethodImpl(MethodImplOptions.NoInlining)]
- internal void CompleteAttachedTransaction()
- {
- Exception error = null;
- if (!this.behavior.TransactionAutoCompleteOnSessionClose)
- {
- error = new Exception();
- if (DiagnosticUtility.ShouldTraceInformation)
- TraceUtility.TraceEvent(TraceEventType.Information,
- TraceCode.TxCompletionStatusAbortedOnSessionClose,
- SR.GetString(SR.TraceCodeTxCompletionStatusAbortedOnSessionClose,
- transaction.Attached.TransactionInformation.LocalIdentifier)
- );
- }
- else if (DiagnosticUtility.ShouldTraceInformation)
- {
- TraceUtility.TraceEvent(TraceEventType.Information,
- TraceCode.TxCompletionStatusCompletedForTACOSC,
- SR.GetString(SR.TraceCodeTxCompletionStatusCompletedForTACOSC,
- transaction.Attached.TransactionInformation.LocalIdentifier)
- );
- }
- transaction.CompletePendingTransaction(transaction.Attached, error);
- transaction.Attached = null;
- }
- QuotaThrottle EnsureQuotaThrottle()
- {
- lock (this.ThisLock)
- {
- if (this.quotaThrottle == null)
- {
- this.quotaThrottle = new QuotaThrottle(ImmutableDispatchRuntime.GotDynamicInstanceContext, this.ThisLock);
- this.quotaThrottle.Owner = "InstanceContext";
- }
- return this.quotaThrottle;
- }
- }
- internal void FaultInternal()
- {
- this.Fault();
- }
- public object GetServiceInstance()
- {
- return this.GetServiceInstance(null);
- }
- public object GetServiceInstance(Message message)
- {
- lock (this.serviceInstanceLock)
- {
- this.ThrowIfClosedOrNotOpen();
- object current = this.userObject;
- if (current != null)
- {
- return current;
- }
- if (this.behavior == null)
- {
- Exception error = new InvalidOperationException(SR.GetString(SR.SFxInstanceNotInitialized));
- if (message != null)
- {
- throw TraceUtility.ThrowHelperError(error, message);
- }
- else
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(error);
- }
- }
- object newUserObject;
- if (message != null)
- {
- newUserObject = this.behavior.GetInstance(this, message);
- }
- else
- {
- newUserObject = this.behavior.GetInstance(this);
- }
- if (newUserObject != null)
- {
- this.SetUserObject(newUserObject);
- }
- return newUserObject;
- }
- }
- public int IncrementManualFlowControlLimit(int incrementBy)
- {
- return this.EnsureQuotaThrottle().IncrementLimit(incrementBy);
- }
- void Load()
- {
- if (this.behavior != null)
- {
- this.behavior.Initialize(this);
- }
- if (this.host != null)
- {
- this.host.BindInstance(this);
- }
- }
- static void NotifyEmpty(InstanceContext instanceContext)
- {
- if (instanceContext.autoClose)
- {
- instanceContext.CloseIfNotBusy();
- }
- }
- static void NotifyIdle(InstanceContext instanceContext)
- {
- instanceContext.CloseIfNotBusy();
- }
- protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
- {
- return new CloseAsyncResult(timeout, callback, state, this);
- }
- protected override void OnEndClose(IAsyncResult result)
- {
- CloseAsyncResult.End(result);
- }
- protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
- {
- return new CompletedAsyncResult(callback, state);
- }
- protected override void OnEndOpen(IAsyncResult result)
- {
- CompletedAsyncResult.End(result);
- }
- protected override void OnClose(TimeSpan timeout)
- {
- channels.Close(timeout);
- this.Unload();
- }
- protected override void OnClosed()
- {
- base.OnClosed();
- ServiceThrottle throttle = this.serviceThrottle;
- if (throttle != null)
- {
- throttle.DeactivateInstanceContext();
- }
- }
- protected override void OnFaulted()
- {
- base.OnFaulted();
- if (this.IsSingleton && (this.host != null))
- {
- this.host.FaultInternal();
- }
- }
- protected override void OnOpen(TimeSpan timeout)
- {
- TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
- }
- protected override void OnOpened()
- {
- base.OnOpened();
- }
- protected override void OnOpening()
- {
- this.Load();
- base.OnOpening();
- }
- public void ReleaseServiceInstance()
- {
- this.ThrowIfDisposedOrNotOpen();
- this.SetUserObject(null);
- }
- void SetUserObject(object newUserObject)
- {
- if (this.behavior != null && !this.wellKnown)
- {
- object oldUserObject = Interlocked.Exchange(ref this.userObject, newUserObject);
- if ((oldUserObject != null) && (this.host != null) && !Object.Equals(oldUserObject, this.host.DisposableInstance))
- {
- this.behavior.ReleaseInstance(this, oldUserObject);
- }
- }
- }
- internal void UnbindRpc(ref MessageRpc rpc)
- {
- if (rpc.InstanceContext == this && rpc.SuccessfullyBoundInstance)
- {
- this.channels.DecrementActivityCount();
- }
- }
- internal void UnbindIncomingChannel(ServiceChannel channel)
- {
- this.channels.RemoveChannel((IChannel)channel.Proxy);
- }
- void Unload()
- {
- this.SetUserObject(null);
- if (this.host != null)
- {
- this.host.UnbindInstance(this);
- }
- }
- class CloseAsyncResult : AsyncResult
- {
- InstanceContext instanceContext;
- TimeoutHelper timeoutHelper;
- public CloseAsyncResult(TimeSpan timeout, AsyncCallback callback, object state, InstanceContext instanceContext)
- : base(callback, state)
- {
- this.timeoutHelper = new TimeoutHelper(timeout);
- this.instanceContext = instanceContext;
- IAsyncResult result = this.instanceContext.channels.BeginClose(this.timeoutHelper.RemainingTime(), PrepareAsyncCompletion(new AsyncCompletion(CloseChannelsCallback)), this);
- if (result.CompletedSynchronously && CloseChannelsCallback(result))
- {
- base.Complete(true);
- }
- }
- public static void End(IAsyncResult result)
- {
- AsyncResult.End<CloseAsyncResult>(result);
- }
- bool CloseChannelsCallback(IAsyncResult result)
- {
- Fx.Assert(object.ReferenceEquals(this, result.AsyncState), "AsyncState should be this");
- this.instanceContext.channels.EndClose(result);
- this.instanceContext.Unload();
- return true;
- }
- }
- }
- }
|