title: current OperationContext is null in WCF Windows Service
body: <p>I am trying to set up a Publish/Subscribe system using WCF and where the WCF server is in a Windows service.  The binding is net.TCP.  The service is providing a "Subscribe" method to the client so the client can register a callback handler to an event that will be raised from a DLL linked to the server.  In the Subscribe method I attempt to get the callback channel using the OperationContext.Current.GetCallbackChannel method.  When I attempt this the OperationContext.Current property returns NULL.</p>
  
  <p>Can anyone tell me under what circumstances this property would return null??  Have I missed setting something up?  I will include the service code and the interface code below.  I am using c# in Visual Studio 2012 and targeting framework 4.5.</p>
  
  <p>Service:</p>
  
  <pre><code>namespace WService
  {
  [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
  public class WcfPublisherService : IWcfPublisherContract
  {
      IOALogic logic = new OAControlExample();
      IWcfSubscriberContract _callback = null;
  
      public void Subscribe()
      {
          _callback = OperationContext.Current.GetCallbackChannel&lt;IWcfSubscriberContract&gt;();
          logic.BarriersChanged += logic_BarriersChanged;
      }
  
      public void UnSubscribe()
      {
          logic.BarriersChanged -= logic_BarriersChanged;
      }
  
      void logic_BarriersChanged(object sender, BarriersChangedEventArgs e)
      {
          _callback.BarriersChanged(e.BarrierLines);
      }
  }
  }
  </code></pre>
  
  <p>Interface:</p>
  
  <pre><code>namespace WService
  {
  [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IWcfSubscriberContract))]
  public interface IWcfPublisherContract
  {
      [OperationContract(IsOneWay=false, IsInitiating=true)]
      void Subscribe();
      [OperationContract(IsOneWay = false, IsTerminating=true)]
      void UnSubscribe();
  }
  
  public interface IWcfSubscriberContract
  {
      [OperationContract(IsOneWay = true)]
      void BarriersChanged(BarrierLines barrierLines);
  }
  }
  </code></pre>
  
  <p>Client:</p>
  
  <pre><code>namespace TestClient
  {
  public partial class Form1 : Form
  {
      WcfPublisherService myService
          = new WcfPublisherService();
  
      ServiceCallback serviceCallback = new ServiceCallback();
  
      public Form1()
      {
          InitializeComponent();
          serviceCallback.NewMessage += serviceCallback_NewMessage;
      }
  
      private delegate void serviceCallback_NewMessageDelegate(object sender, NewMessageEventArgs e);
      void serviceCallback_NewMessage(object sender, NewMessageEventArgs e)
      {
          if (textBox1.InvokeRequired)
          {
              textBox1.Invoke(new serviceCallback_NewMessageDelegate(serviceCallback_NewMessage), new object[] {sender, e});
          }
          else
          {
              if (textBox1.Text.Trim().Length &gt; 1)
              {
                  textBox1.Text += Environment.NewLine;
              }
              textBox1.Text += e.Msg;
          }
      }
  
      private void button1_Click(object sender, EventArgs e)
      {
          myService.Subscribe();
      }
  
      private void button2_Click(object sender, EventArgs e)
      {
          myService.UnSubscribe();
      }
  }
  
  [CallbackBehaviorAttribute(UseSynchronizationContext = false)]
  class ServiceCallback : IWcfSubscriberContract
  {
      public delegate void NewMessageEventHandler(object sender, NewMessageEventArgs e);
      public event NewMessageEventHandler NewMessage;
      protected virtual void OnNewMessage(string msg)
      {
          if (NewMessage != null)
          {
              NewMessage(this, new NewMessageEventArgs(msg));
          }
      }
  
      public void BarriersChanged(OA.BarrierLines barrierLines)
      {
          OnNewMessage("new barrier lines");
      }
  }
  
  public class NewMessageEventArgs : EventArgs
  {
      public NewMessageEventArgs(string msg)
      {
          this.Msg = msg;
      }
      public string Msg { get; set; }
  }
  }
  </code></pre>
  
  <p><em><strong></em>**<em>*</em>**<em>*</em>**<em>*</em></strong>    New Edit    <strong><em>*</em>**<em>*</em>**<em>*</em>**<em>*</em>**<em>*</em>**</strong>
  Thanks to SalientBrain's suggestions, I have made considerable changes to my project because I realized the service had to be long running and continually running even if no clients are connected so I changed it to a singleton.  Even so, my original problem still persists.  SalientBrain has asked to see my config file so I will include it below along with all the other pertinent files.  I've stripped it out to conserve space, but I don't think I removed anything important.  The error occurs in Subscribe method of the PulisherService class. I hope it is something stupid I did in the config file.  Well, here it is:</p>
  
  <p>Config:</p>
  
  <pre><code>    &lt;configuration&gt;
      &lt;startup&gt; 
          &lt;supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /&gt;
      &lt;/startup&gt;
      &lt;system.serviceModel&gt;
          &lt;behaviors&gt;
              &lt;serviceBehaviors&gt;
                  &lt;behavior name="WService.WCFPublisherServiceBehavior"&gt;
                      &lt;serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" /&gt;
                      &lt;serviceDebug includeExceptionDetailInFaults="false" /&gt;
                  &lt;/behavior&gt;
              &lt;/serviceBehaviors&gt;
          &lt;/behaviors&gt;
          &lt;services&gt;
              &lt;service behaviorConfiguration="WService.WCFPublisherServiceBehavior"
                  name="WService.WcfPublisherService"&gt;
                  &lt;endpoint address="" binding="netTcpBinding" bindingConfiguration=""
                      name="NetTcpBindingEndpoint" contract="WService.IWcfPublisherContract"&gt;
                      &lt;identity&gt;
                          &lt;dns value="localhost" /&gt;
                      &lt;/identity&gt;
                  &lt;/endpoint&gt;
                  &lt;endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""
                      name="MexTcpBindingEndpoint" contract="IMetadataExchange" /&gt;
                  &lt;host&gt;
                      &lt;baseAddresses&gt;
                          &lt;add baseAddress="net.tcp://localhost:8523/Publisher" /&gt;
                      &lt;/baseAddresses&gt;
                  &lt;/host&gt;
              &lt;/service&gt;
          &lt;/services&gt;
      &lt;/system.serviceModel&gt;
  &lt;/configuration&gt;
  </code></pre>
  
  <p>WcfContracts:</p>
  
  <pre><code>    namespace WService
  {
      [ServiceContract(SessionMode = SessionMode.Allowed, CallbackContract = typeof(IWcfSubscriberContract))]
      public interface IWcfPublisherContract
      {
          [OperationContract(IsOneWay=false)]
          void Subscribe(string key);
          [OperationContract(IsOneWay = false)]
          void UnSubscribe(string key);
      }
  
      public interface IWcfSubscriberContract
      {
          [OperationContract(IsOneWay = true)]
          void BarriersChanged(BarrierLines barrierLines);
      }
  }
  </code></pre>
  
  <p>WcfService:</p>
  
  <pre><code>    namespace WService
  {
      [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
      public class WcfPublisherService : IWcfPublisherContract
      {
          private static WcfPublisherService _instance = null;
          private IOALogic _logic = null;
          private Dictionary&lt;string, IWcfSubscriberContract&gt; _callbacks
              = new Dictionary&lt;string, IWcfSubscriberContract&gt;();
          private ReaderWriterLock _callbacksLock = new ReaderWriterLock();
  
          private WcfPublisherService() { }
  
          public static WcfPublisherService TheInstance()
          {
              if (_instance == null)
              {
                  _instance = new WcfPublisherService();
              }
              return _instance;
          }
  
          public void StopWcf()
          {
              _logic.StopRequest();
          }
  
          public void StartWcf(IOALogic logic)
          {
              _logic = logic;
              _logic.BarriersChanged += logic_BarriersChanged;
              ThreadPool.QueueUserWorkItem(new WaitCallback(StartWork), null);
          }
  
          public void StartWork(object state)
          {
              _logic.Run();
          }
  
          public void Subscribe(string key)
          {
              OperationContext context = OperationContext.Current;
              // The above line returns null ***********************************************
              _callbacksLock.AcquireWriterLock(2000);
              if (_callbacksLock.IsWriterLockHeld)
              {
                  _callbacks.Add(key, context.GetCallbackChannel&lt;IWcfSubscriberContract&gt;());
                  // The above line throws a null execption because context is null  ********
                  _callbacksLock.ReleaseWriterLock();
              }
          }
  
          public void UnSubscribe(string key)
          {
              _callbacksLock.AcquireWriterLock(2000);
              if (_callbacksLock.IsWriterLockHeld)
              {
                  _callbacks.Remove(key);
                  _callbacksLock.ReleaseWriterLock();
              }
          }
  
          void logic_BarriersChanged(object sender, BarriersChangedEventArgs e)
          {
              _callbacksLock.AcquireReaderLock(1000);
              if (_callbacksLock.IsReaderLockHeld)
              {
                  try
                  {
                      foreach (IWcfSubscriberContract callback in _callbacks.Values)
                      {
                          callback.BarriersChanged(e.BarrierLines);
                      }
                  }
                  finally
                  {
                      _callbacksLock.ReleaseReaderLock();
                  }
              }
          }
      }
  }
  </code></pre>
  
  <p>WindowsService:</p>
  
  <pre><code>    namespace WService
  {
      public partial class WService : ServiceBase
      {
          internal static ServiceHost _serviceHost = null;
          internal static IOALogic _logic = new OAControlExample();
  
          public WService()
          {
              InitializeComponent();
          }
  
          protected override void OnStart(string[] args)
          {
              if (_serviceHost != null)
              {
                  _serviceHost.Close();
              }
  
              _serviceHost = new ServiceHost(WcfPublisherService.TheInstance());
              WcfPublisherService.TheInstance().StartWcf(_logic);
              _serviceHost.Open();
          }
  
          protected override void OnStop()
          {
              if (WcfPublisherService.TheInstance() != null)
              {
                  WcfPublisherService.TheInstance().StopWcf();
              }
              if (_serviceHost != null)
              {
                  _serviceHost.Close();
                  _serviceHost = null;
              }
          }
      }
  }
  </code></pre>
  
  <p>TestForm:</p>
  
  <pre><code>    namespace TestClient
  {
      public partial class Form1 : Form
      {
          ServiceCallback serviceCallback = new ServiceCallback();
  
          public Form1()
          {
              InitializeComponent();
  
              serviceCallback.NewMessage += serviceCallback_NewMessage;
          }
  
          private delegate void serviceCallback_NewMessageDelegate(object sender, NewMessageEventArgs e);
          void serviceCallback_NewMessage(object sender, NewMessageEventArgs e)
          {
              if (textBox1.InvokeRequired)
              {
                  textBox1.Invoke(new serviceCallback_NewMessageDelegate(serviceCallback_NewMessage), new object[] {sender, e});
              }
              else
              {
                  if (textBox1.Text.Trim().Length &gt; 1)
                  {
                      textBox1.Text += Environment.NewLine;
                  }
                  textBox1.Text += e.Msg;
              }
          }
  
          private void button1_Click(object sender, EventArgs e)
          {
              serviceCallback.Subscribe();
          }
  
          private void button2_Click(object sender, EventArgs e)
          {
              serviceCallback.Unsubscribe();
          }
      }
  }
  </code></pre>
  
  <p>TestCallbackClass:</p>
  
  <pre><code>    namespace TestClient
  {
      [CallbackBehaviorAttribute(UseSynchronizationContext = true)]
      class ServiceCallback : IWcfSubscriberContract
      {
          WcfPublisherService myService
              = WcfPublisherService.TheInstance();
          string callbackKey = Guid.NewGuid().ToString();
  
          public delegate void NewMessageEventHandler(object sender, NewMessageEventArgs e);
          public event NewMessageEventHandler NewMessage;
          protected virtual void OnNewMessage(string msg)
          {
              if (NewMessage != null)
              {
                  NewMessage(this, new NewMessageEventArgs(msg));
              }
          }
  
          public void Subscribe()
          {
              try
              {
                  myService.Subscribe(callbackKey);
              }
              catch (Exception ex)
              {
                  OnNewMessage("exception: " + ex.Message);
              }
          }
  
          public void Unsubscribe()
          {
              try
              {
                  myService.UnSubscribe(callbackKey);
              }
              catch (Exception ex)
              {
                  OnNewMessage("exception: " + ex.Message);
              }
          }
  
          public void BarriersChanged(OAInterface.BarrierLines barrierLines)
          {
              OnNewMessage("new barrier lines");
          }
      }
  
      public class NewMessageEventArgs : EventArgs
      {
          public NewMessageEventArgs(string msg)
          {
              this.Msg = msg;
          }
          public string Msg { get; set; }
      }
  }
  </code></pre>