Will creating a background thread in a WCF service during a call, take up a thread in the ASP .NET t
- by Nate Pinchot
The following code is part of a WCF service. Will eventWatcher take up a thread in the ASP .NET thread pool, even if it is set IsBackground = true?
/// <summary>
/// Provides methods to work with the PhoneSystem web services SDK.
/// This is a singleton since we need to keep track of what lines (extensions) are open.
/// </summary>
public sealed class PhoneSystemWebServiceFactory : IDisposable
{
// singleton instance reference
private static readonly PhoneSystemWebServiceFactory instance = new PhoneSystemWebServiceFactory();
private static readonly object l = new object();
private static volatile Hashtable monitoredExtensions = new Hashtable();
private static readonly PhoneSystemWebServiceClient webServiceClient = CreateWebServiceClient();
private static volatile bool isClientRegistered;
private static volatile string clientHandle;
private static readonly Thread eventWatcherThread = new Thread(EventPoller) {IsBackground = true};
#region Constructor
// these constructors are hacks to make the C# compiler not mark beforefieldinit
// more info: http://www.yoda.arachsys.com/csharp/singleton.html
static PhoneSystemWebServiceFactory()
{
}
PhoneSystemWebServiceFactory()
{
}
#endregion
#region Properties
/// <summary>
/// Gets a thread safe instance of PhoneSystemWebServiceFactory
/// </summary>
public static PhoneSystemWebServiceFactory Instance
{
get { return instance; }
}
#endregion
#region Private methods
/// <summary>
/// Create and configure a PhoneSystemWebServiceClient with basic http binding and endpoint from app settings.
/// </summary>
/// <returns>PhoneSystemWebServiceClient</returns>
private static PhoneSystemWebServiceClient CreateWebServiceClient()
{
string url = ConfigurationManager.AppSettings["PhoneSystemWebService_Url"];
if (string.IsNullOrEmpty(url))
{
throw new ConfigurationErrorsException(
"The AppSetting \"PhoneSystemWebService_Url\" could not be found. Check the application configuration and ensure that the element exists. Example: <appSettings><add key=\"PhoneSystemWebService_Url\" value=\"http://xyz\" /></appSettings>");
}
return new PhoneSystemWebServiceClient(new BasicHttpBinding(), new EndpointAddress(url));
}
#endregion
#region Event poller
public static void EventPoller()
{
while (true)
{
if (Thread.CurrentThread.ThreadState == ThreadState.Aborted ||
Thread.CurrentThread.ThreadState == ThreadState.AbortRequested ||
Thread.CurrentThread.ThreadState == ThreadState.Stopped ||
Thread.CurrentThread.ThreadState == ThreadState.StopRequested)
break;
// get events
//webServiceClient.GetEvents(clientHandle, 30, 100);
}
Thread.Sleep(5000);
}
#endregion
#region Client registration methods
private static void RegisterClientIfNeeded()
{
if (isClientRegistered)
{
return;
}
lock (l)
{
// double lock check
if (isClientRegistered)
{
return;
}
//clientHandle = webServiceClient.RegisterClient("PhoneSystemWebServiceFactoryInternal", null);
isClientRegistered = true;
}
}
private static void UnregisterClient()
{
if (!isClientRegistered)
{
return;
}
lock (l)
{
// double lock check
if (!isClientRegistered)
{
return;
}
//webServiceClient.UnegisterClient(clientHandle);
}
}
#endregion
#region Phone extension methods
public bool SubscribeToEventsForExtension(string extension)
{
if (monitoredExtensions.Contains(extension))
{
return false;
}
lock (monitoredExtensions.SyncRoot)
{
// double lock check
if (monitoredExtensions.Contains(extension))
{
return false;
}
RegisterClientIfNeeded();
// open line so we receive events for extension
LineInfo lineInfo;
try
{
//lineInfo = webServiceClient.OpenLine(clientHandle, extension);
}
catch (FaultException<PhoneSystemWebSDKErrorDetail>)
{
// TODO: log error
return false;
}
// add extension to list of monitored extensions
//monitoredExtensions.Add(extension, lineInfo.lineID);
monitoredExtensions.Add(extension, 1);
// start event poller thread if not already started
if (eventWatcherThread.ThreadState == ThreadState.Stopped || eventWatcherThread.ThreadState == ThreadState.Unstarted)
{
eventWatcherThread.Start();
}
return true;
}
}
public bool UnsubscribeFromEventsForExtension(string extension)
{
if (!monitoredExtensions.Contains(extension))
{
return false;
}
lock (monitoredExtensions.SyncRoot)
{
if (!monitoredExtensions.Contains(extension))
{
return false;
}
// close line
try
{
//webServiceClient.CloseLine(clientHandle, (int) monitoredExtensions[extension]);
}
catch (FaultException<PhoneSystemWebSDKErrorDetail>)
{
// TODO: log error
return false;
}
// remove extension from list of monitored extensions
monitoredExtensions.Remove(extension);
// if we are not monitoring anything else, stop the poller and unregister the client
if (monitoredExtensions.Count == 0)
{
eventWatcherThread.Abort();
UnregisterClient();
}
return true;
}
}
public bool IsExtensionMonitored(string extension)
{
lock (monitoredExtensions.SyncRoot)
{
return monitoredExtensions.Contains(extension);
}
}
#endregion
#region Dispose
public void Dispose()
{
lock (l)
{
// close any open lines
var extensions = monitoredExtensions.Keys.Cast<string>().ToList();
while (extensions.Count > 0)
{
UnsubscribeFromEventsForExtension(extensions[0]);
extensions.RemoveAt(0);
}
if (!isClientRegistered)
{
return;
}
// unregister web service client
UnregisterClient();
}
}
#endregion
}