public DurableInstanceContextBindingElement(BindingElement other) : base(other) { DurableInstanceContextBindingElement otherBindingElement = other as DurableInstanceContextBindingElement; if (otherBindingElement != null) { this.contextStoreLocation = otherBindingElement.contextStoreLocation; this.contextType = otherBindingElement.contextType; if ((contextStoreLocation == null) || (contextStoreLocation.Trim().Length == 0)) { InitializeContextStoreLocation(); } else { // Throw if the specified contextStoreLocation is // invalid. if (!Directory.Exists(contextStoreLocation)) { throw new InvalidOperationException( ResourceHelper.GetString(@"ExInvalidContextStorePath")); } } } else { this.contextType = ContextType.MessageHeader; InitializeContextStoreLocation(); } }
public void InitializeInstanceContext(InstanceContext instanceContext, System.ServiceModel.Channels.Message message, IContextChannel channel) { //Look if the Client has given us a unique ID to add to this InstanceContext int headerIndex = message.Headers.FindHeader(CustomHeader.HeaderName, CustomHeader.HeaderNamespace); String headerId = null; if (headerIndex != -1) { headerId = message.Headers.GetHeader <string>(headerIndex); } if (headerId == null) { //If no header was sent by the Client, then create a new one and assign it to this InstanceContext. headerId = Guid.NewGuid().ToString(); Utility.WriteMessageToConsole(String.Format(ResourceHelper.GetString("NoHeaderFound"))); } Utility.WriteMessageToConsole(String.Format(ResourceHelper.GetString("InstanceContextAddedToCache"), headerId)); //Add this to the Cache this.instanceContextCache[headerId] = instanceContext; //Register the Closing event of this InstancContext so it can be removed from the collection instanceContext.Closing += this.RemoveInstanceContext; IExtension <InstanceContext> customLeaseExtension = new CustomLeaseExtension(timeout, headerId); instanceContext.Extensions.Add(customLeaseExtension); }
/// <summary> /// This implements a PerCall InstanceContextMode behavior. If a cached InstanceContext is not found /// then WCF will create a new one. /// </summary> public InstanceContext GetExistingInstanceContext(System.ServiceModel.Channels.Message message, IContextChannel channel) { //Per Session behavior //To implement a PerSession behavior (If underlyin binding supports it) where in all //methods from one ChannelFactory will be serviced by the same InstanceContext //Check if the incoming request has the InstanceContext id it wants to connect with. if (message.Headers.FindHeader(CustomHeader.HeaderName, CustomHeader.HeaderNamespace) != -1) { String sharingId = message.Headers.GetHeader <string>(CustomHeader.HeaderName, CustomHeader.HeaderNamespace); if (sharingId != null && instanceContextCache.ContainsKey(sharingId)) { Utility.WriteMessageToConsole(String.Format(ResourceHelper.GetString("InstanceContextLookup"), sharingId)); //Retrieve the InstanceContext from the map InstanceContext context = instanceContextCache[sharingId]; if (context != null) { //Before returning, stop the timer on this InstanceContext CustomLeaseExtension extension = context.Extensions.Find <CustomLeaseExtension>(); Utility.WriteMessageToConsole(String.Format(ResourceHelper.GetString("StopInstanceContextIdleTimer"), sharingId)); extension.StopTimer(); Utility.WriteMessageToConsole(ResourceHelper.GetString("CachedInstanceContextFound")); return(instanceContextCache[sharingId]); } } } //No existing InstanceContext was found so return null and WCF will create a new one. return(null); }
public static IStorageManager GetStorageManager(Type storageManagerType) { IStorageManager storageManager = null; if (storageManagerType == null) { return(new SqlServerStorageManager()); } else { object obj = Activator.CreateInstance(storageManagerType); // Throw if the specified storage manager type does not // implement IStorageManager. if (obj is IStorageManager) { storageManager = (IStorageManager)obj; } else { throw new InvalidOperationException( ResourceHelper.GetString("ExInvalidStorageManager")); } return(storageManager); } }
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase) { // Create an instance of the ObjectPoolInstanceProvider. ObjectPoolingInstanceProvider instanceProvider = new ObjectPoolingInstanceProvider(description.ServiceType, minPoolSize); // Forward the call if we created a ServiceThrottlingBehavior. if (this.throttlingBehavior != null) { ((IServiceBehavior)this.throttlingBehavior).ApplyDispatchBehavior(description, serviceHostBase); } // In case there was already a ServiceThrottlingBehavior (this.throttlingBehavior==null), // it should have initialized a single ServiceThrottle on all ChannelDispatchers. As // we loop through the ChannelDispatchers, we verify that and modify the ServiceThrottle // to guard MaxPoolSize. ServiceThrottle throttle = null; foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers) { ChannelDispatcher cd = cdb as ChannelDispatcher; if (cd != null) { // Make sure there is exactly one throttle used by all endpoints. // If there were others, we could not enforce MaxPoolSize. if ((this.throttlingBehavior == null) && (this.maxPoolSize != Int32.MaxValue)) { if (throttle == null) { throttle = cd.ServiceThrottle; } if (cd.ServiceThrottle == null) { throw new InvalidOperationException(ResourceHelper.GetString("ExNullThrottle")); } if (throttle != cd.ServiceThrottle) { throw new InvalidOperationException(ResourceHelper.GetString("ExDifferentThrottle")); } } foreach (EndpointDispatcher ed in cd.Endpoints) { // Assign it to DispatchBehavior in each endpoint. ed.DispatchRuntime.InstanceProvider = instanceProvider; } } } // Set the MaxConcurrentInstances to limit the number of items that will // ever be requested from the pool. if ((throttle != null) && (throttle.MaxConcurrentInstances > this.maxPoolSize)) { throttle.MaxConcurrentInstances = this.maxPoolSize; } }
/// <summary> /// Timer elapsed event handler. /// </summary> void idleTimer_Elapsed(object sender, ElapsedEventArgs args) { lock (thisLock) { StopTimer(); isIdle = true; Utility.WriteMessageToConsole( ResourceHelper.GetString("MsgLeaseExpired")); callback(owner); } }
public void RemoveInstanceContext(object o, EventArgs args) { InstanceContext context = o as InstanceContext; CustomLeaseExtension extension = context.Extensions.Find <CustomLeaseExtension>(); String id = (extension != null) ? extension.InstanceId : null; if (this.instanceContextCache[id] != null) { Utility.WriteMessageToConsole(String.Format(ResourceHelper.GetString("InstanceContextRemovedFromCache"), id)); this.instanceContextCache.Remove(id); } }
TChannel GetChannelWrapper(TChannel innerChannel) { if (innerChannel == null) { return(null); } if (typeof(TChannel) == typeof(IInputChannel)) { return((TChannel)(object)new DurableInstanceContextInputChannel(this, contextType, (IInputChannel)innerChannel)); } else if (typeof(TChannel) == typeof(IInputSessionChannel)) { return((TChannel)(object)new DurableInstanceContextInputSessionChannel(this, contextType, (IInputSessionChannel)innerChannel)); } else if (typeof(TChannel) == typeof(IReplyChannel)) { return((TChannel)(object)new DurableInstanceContextReplyChannel(this, contextType, (IReplyChannel)innerChannel)); } else if (typeof(TChannel) == typeof(IReplySessionChannel)) { return((TChannel)(object)new DurableInstanceContextReplySessionChannel( this, contextType, (IReplySessionChannel)innerChannel)); } else if (typeof(TChannel) == typeof(IDuplexChannel)) { return((TChannel)(object)new DurableInstanceContextDuplexChannel(this, contextType, (IDuplexChannel)innerChannel, contextStoreLocation)); } else if (typeof(TChannel) == typeof(IDuplexSessionChannel)) { return((TChannel)(object)new DurableInstanceContextDuplexSessionChannel( this, contextType, (IDuplexSessionChannel)innerChannel, contextStoreLocation)); } else { throw new NotSupportedException( ResourceHelper.GetString("ExChannelNotSupported")); } }
string GetConnectionString() { string connectionString = ConfigurationManager.AppSettings[DurableInstanceContextUtility.ConnectionString]; if (connectionString == null) { throw new InvalidOperationException( ResourceHelper.GetString("ExConnectionStringNotFound")); } return(connectionString); }
public void Validate(ServiceDescription description, ServiceHostBase serviceHostBase) { // Throw if the instance context mode is Single. ServiceBehaviorAttribute serviceBehavior = description.Behaviors.Find <ServiceBehaviorAttribute>(); if (serviceBehavior != null && serviceBehavior.InstanceContextMode == InstanceContextMode.Single) { throw new InvalidOperationException( ResourceHelper.GetString("ExInvalidContext")); } }
//If the context type is set to HttpCookie this //function verifies that the current binding //is using the HTTP transport. void ValidateTransport(CustomBinding binding) { if (this.contextType == ContextType.HttpCookie) { HttpTransportBindingElement httpTransport = binding.Elements.Find <HttpTransportBindingElement>(); if (httpTransport == null) { throw new InvalidOperationException( ResourceHelper.GetString("ExInvalidTransport")); } } }
/// <summary> /// Puts an object back to the pool. /// </summary> /// <remarks> /// This method is invoked by WCF runtime. /// </remarks> public void ReleaseInstance(InstanceContext instanceContext, object instance) { lock (poolLock) { // Check whether the object can be pooled. // Call the Deactivate method if possible. if (instance is IObjectControl) { IObjectControl objectControl = (IObjectControl)instance; objectControl.Deactivate(); if (objectControl.CanBePooled) { pool.Push(instance); #if (DEBUG) WritePoolMessage( ResourceHelper.GetString("MsgObjectPooled")); #endif } else { #if (DEBUG) WritePoolMessage( ResourceHelper.GetString("MsgObjectWasNotPooled")); #endif } } else { pool.Push(instance); #if (DEBUG) WritePoolMessage( ResourceHelper.GetString("MsgObjectPooled")); #endif } activeObjectsCount--; if (activeObjectsCount == 0) { idleTimer.Start(); } } availableCount.Release(1); }
void IInstanceProvider.ReleaseInstance(InstanceContext instanceContext, object instance) { lock (poolLock) { pool.Push(instance); activeObjectsCount--; WritePoolMessage(ResourceHelper.GetString("MsgObjectPooled")); // When the service goes completely idle (no requests are being processed), // the idle timer is started if (activeObjectsCount == 0) { idleTimer.Start(); } } }
/// <summary> /// Implements the logic for returning an object /// from the pool. /// </summary> private object GetObjectFromThePool() { bool didNotTimeout = availableCount.WaitOne(creationTimeout, true); if (didNotTimeout) { object obj = null; lock (poolLock) { if (pool.Count != 0) { obj = pool.Pop(); activeObjectsCount++; } else if (pool.Count == 0) { if (activeObjectsCount < maxPoolSize) { obj = CreateNewPoolObject(); activeObjectsCount++; #if (DEBUG) WritePoolMessage( ResourceHelper.GetString("MsgNewObject")); #endif } } idleTimer.Stop(); } // Call the Activate method if possible. if (obj is IObjectControl) { ((IObjectControl)obj).Activate(); } return(obj); } throw new TimeoutException( ResourceHelper.GetString("ExObjectCreationTimeout")); }
public bool IsIdle(InstanceContext instanceContext) { lock (thisLock) { if (isIdle) { Utility.WriteMessageToConsole( ResourceHelper.GetString("MsgIdle")); } else { Utility.WriteMessageToConsole( ResourceHelper.GetString("MsgNotIdle")); } bool idleCopy = isIdle; isIdle = false; return(idleCopy); } }
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { // Durable instancing could not be used with // singleton instancing. ServiceBehaviorAttribute serviceBehavior = serviceDescription.Behaviors.Find <ServiceBehaviorAttribute>(); if (serviceBehavior != null && serviceBehavior.InstanceContextMode == InstanceContextMode.Single) { throw new InvalidOperationException( ResourceHelper.GetString("ExSingeltonInstancingNotSupported")); } // Use the StorageManagerFactory to create an instance of a // storage manager. IStorageManager storageManager = StorageManagerFactory.GetStorageManager(storageManagerType); InstanceContextInitializer contextInitializer = new InstanceContextInitializer(storageManager); InstanceProvider instanceProvider = new InstanceProvider(serviceDescription.ServiceType); foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers) { ChannelDispatcher cd = cdb as ChannelDispatcher; if (cd != null) { foreach (EndpointDispatcher ed in cd.Endpoints) { ed.DispatchRuntime.InstanceContextInitializers.Add(contextInitializer); ed.DispatchRuntime.InstanceProvider = instanceProvider; } } } }
//Reads the durable instance context id from the incoming //messages. protected string ReadContextId(Message message) { IContextManager contextManager = ContextManagerFactory.CreateContextManager(contextType, this.contextStoreLocation, this.endpointAddress); string contextId = contextManager.ReadContext(message); if (contextId == null) { throw new CommunicationException( ResourceHelper.GetString("ExContextNotFound")); } // Add the context id to the properties collection of the Message. // This way we can pass the context id to the service model layer in a // consistent manner regardless of the context type. message.Properties.Add(DurableInstanceContextUtility.ContextIdProperty, contextId); return(contextId); }
void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase) { if (this.maxPoolSize < this.minPoolSize) { throw new InvalidOperationException(ResourceHelper.GetString("ExMinLargerThanMax")); } // throw if the instance context mode is Single ServiceBehaviorAttribute serviceBehavior = description.Behaviors.Find <ServiceBehaviorAttribute>(); if (serviceBehavior != null && serviceBehavior.InstanceContextMode == InstanceContextMode.Single) { throw new InvalidOperationException(ResourceHelper.GetString("ExInvalidContext")); } // We need ServiceThrottlingBehavior to run before us, because it properly // initializes the ServiceThrottle property of the endpoints. If there is // no ServiceThrottlingBehavior, we will create one and run it ourselves. // If there is one, we validate that it comes before us. int throttlingIndex = this.GetBehaviorIndex(description, typeof(ServiceThrottlingBehavior)); if (throttlingIndex == -1) { this.throttlingBehavior = new ServiceThrottlingBehavior(); this.throttlingBehavior.MaxConcurrentInstances = this.MaxPoolSize; // Forward the call if we created a ServiceThrottlingBehavior. ((IServiceBehavior)this.throttlingBehavior).Validate(description, serviceHostBase); } else { int poolingIndex = this.GetBehaviorIndex(description, typeof(ObjectPoolingAttribute)); if (poolingIndex < throttlingIndex) { throw new InvalidOperationException(ResourceHelper.GetString("ExThrottleBeforePool")); } } }
// Clean up procedure void idleTimer_Elapsed(object sender, ElapsedEventArgs args) { idleTimer.Stop(); lock (poolLock) { if (activeObjectsCount == 0) { while (pool.Count > minPoolSize) { WritePoolMessage(ResourceHelper.GetString("MsgObjectRemoving")); object removedItem = pool.Pop(); if (removedItem is IDisposable) { ((IDisposable)removedItem).Dispose(); } } } } }
object IInstanceProvider.GetInstance(InstanceContext instanceContext, Message message) { object obj = null; lock (poolLock) { if (pool.Count > 0) { obj = pool.Pop(); } else { obj = CreateNewPoolObject(); } activeObjectsCount++; } WritePoolMessage(ResourceHelper.GetString("MsgNewObject")); idleTimer.Stop(); return(obj); }
/// <summary> /// Clean up procedure. /// </summary> void idleTimer_Elapsed(object sender, ElapsedEventArgs args) { idleTimer.Stop(); lock (poolLock) { if (activeObjectsCount == 0) { // Remove the surplus objects. if (pool.Count > minPoolSize) { while (pool.Count != minPoolSize) { #if (DEBUG) WritePoolMessage( ResourceHelper.GetString("MsgObjectRemoving")); #endif object removedItem = pool.Pop(); if (removedItem is IDisposable) { ((IDisposable)removedItem).Dispose(); } } } else if (pool.Count < minPoolSize) { // Reinitialize the missing objects. while (pool.Count != minPoolSize) { pool.Push(CreateNewPoolObject()); } } } } }
protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey) { base.DeserializeElement(reader, serializeCollectionKey); string attributeValue; attributeValue = reader.GetAttribute(DurableInstanceContextUtility.ContextStoreLocation); if (attributeValue != null) { this.contextStoreLocation = attributeValue; attributeValue = null; } attributeValue = reader.GetAttribute(DurableInstanceContextUtility.ContextType); if (attributeValue != null) { switch (attributeValue) { case DurableInstanceContextUtility.HttpCookie: this.contextType = ContextType.HttpCookie; break; case DurableInstanceContextUtility.MessageHeader: this.contextType = ContextType.MessageHeader; break; default: throw new InvalidOperationException( ResourceHelper.GetString(@"ExInvalidContextType")); } } }
//Returns a new context id. This method initially tries to //read the context id from an existing file. If the context //id is available this simply returns that. Otherwise this creates //a new context id (Guid) and returns it. This also saves the newly //created context id into a file whose file name is created //according to the endpoint address. protected string GetContextId() { // Build the file name. string fileName = this.endpointAddress.ToString(); ReplaceInvalidChars(ref fileName); fileName = string.Format(CultureInfo.InvariantCulture, @"{0}.txt", fileName); string absFilePath = string.Format(CultureInfo.InvariantCulture, @"{0}\{1}", this.contextStoreLocation, fileName); // Synchronize access to this file using a mutex. Mutex fileMutex = new Mutex(false, fileName); fileMutex.WaitOne(); string contextId = null; if (File.Exists(absFilePath)) { // Try to read the content from the file. using (StreamReader textReader = File.OpenText(absFilePath)) { if (textReader != null) { contextId = textReader.ReadLine(); try { Guid guid = new Guid(contextId); } catch (Exception e) { throw new InvalidOperationException( ResourceHelper.GetString("ExInvalidContextId"), e); } } } } else { // Create a new context id and write it to a file in the // directory specified by contextStorageLocation. contextId = Guid.NewGuid().ToString(); UTF8Encoding encoding = new UTF8Encoding(true, false); byte[] buffer = encoding.GetBytes(contextId); // Do not other processes to access this file until // we are done. FileStream fs = new FileStream(absFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None); fs.Write(buffer, 0, buffer.Length); fs.Close(); } // Release the mutex. fileMutex.ReleaseMutex(); return(contextId); }
protected override TChannel OnCreateChannel(EndpointAddress address, Uri via) { TChannel innerChannel = innerChannelFactory.CreateChannel(address, via); if (typeof(TChannel) == typeof(IOutputChannel)) { return((TChannel)(object)new DurableInstanceContextOutputChannel( this, contextType, (IOutputChannel)innerChannel, contextStoreLocation)); } else if (typeof(TChannel) == typeof(IOutputSessionChannel)) { return((TChannel)(object)new DurableInstanceContextOutputSessionChannel( this, contextType, (IOutputSessionChannel)innerChannel, contextStoreLocation)); } else if (typeof(TChannel) == typeof(IRequestChannel)) { return((TChannel)(object)new DurableInstanceContextRequestChannel( this, contextType, (IRequestChannel)innerChannel, contextStoreLocation)); } else if (typeof(TChannel) == typeof(IRequestSessionChannel)) { return((TChannel)(object)new DurableInstanceContextRequestSessionChannel( this, contextType, (IRequestSessionChannel)innerChannel, contextStoreLocation)); } else if (typeof(TChannel) == typeof(IDuplexChannel)) { return((TChannel)(object)new DurableInstanceContextDuplexChannel( this, contextType, (IDuplexChannel)innerChannel, contextStoreLocation)); } else if (typeof(TChannel) == typeof(IDuplexSessionChannel)) { return((TChannel)(object)new DurableInstanceContextDuplexSessionChannel( this, contextType, (IDuplexSessionChannel)innerChannel, contextStoreLocation)); } else { throw new NotSupportedException( ResourceHelper.GetString("ExChannelNotSupported")); } }