actuel OperationContext est nulle dans WCF Service Windows

Je suis en train de mettre en place un Publier/Souscrire système en utilisant WCF et de la FMC serveur est dans un service Windows. La liaison est net.TCP. Le service est de fournir un "Abonnez-vous" méthode pour le client le client peut ainsi enregistrer un gestionnaire de rappel pour un événement qui sera déclenché à partir d'une DLL lié au serveur. Dans la méthode Subscribe j'essayerai d'obtenir le rappel de canal à l'aide de la OperationContext.Actuel.GetCallbackChannel méthode. Lorsque je tente ce la OperationContext.Actuel de la propriété renvoie la valeur NULL.

Quelqu'un peut me dire dans quelles circonstances cette propriété serait de retour est nulle?? Ai-je manqué de mettre quelque chose en place? Je vais inclure le code de service et le code de l'interface ci-dessous. Je suis à l'aide de c# dans Visual Studio 2012 et le ciblage framework 4.5.

Service:

namespace WService
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class WcfPublisherService : IWcfPublisherContract
{
    IOALogic logic = new OAControlExample();
    IWcfSubscriberContract _callback = null;

    public void Subscribe()
    {
        _callback = OperationContext.Current.GetCallbackChannel<IWcfSubscriberContract>();
        logic.BarriersChanged += logic_BarriersChanged;
    }

    public void UnSubscribe()
    {
        logic.BarriersChanged -= logic_BarriersChanged;
    }

    void logic_BarriersChanged(object sender, BarriersChangedEventArgs e)
    {
        _callback.BarriersChanged(e.BarrierLines);
    }
}
}

Interface:

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);
}
}

Client:

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 > 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; }
}
}

********* Nouvelle Édition ***************
Grâce à SalientBrain suggestions, j'ai apporté d'importants changements à mon projet car j'ai réalisé que le service devait être long et à fonctionnement continu, même si aucun client n'est connecté, donc je l'ai changé pour un singleton. De même, mon problème persiste. SalientBrain a demandé à voir mon fichier de config donc je vais l'inclure ci-dessous avec tous les autres fichiers pertinents. J'ai dépouillé pour économiser de l'espace, mais je ne pense pas que j'ai supprimé quelque chose d'important. L'erreur se produit dans Abonnez-vous la méthode de la PulisherService classe. J'espère que c'est quelque chose de stupide, je l'ai fait dans le fichier de configuration. Eh bien, ici, c'est:

Config:

    <configuration>
<startup> 
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="WService.WCFPublisherServiceBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="WService.WCFPublisherServiceBehavior"
name="WService.WcfPublisherService">
<endpoint address="" binding="netTcpBinding" bindingConfiguration=""
name="NetTcpBindingEndpoint" contract="WService.IWcfPublisherContract">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""
name="MexTcpBindingEndpoint" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8523/Publisher" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>

WcfContracts:

    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);
}
}

WcfService:

    namespace WService
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class WcfPublisherService : IWcfPublisherContract
{
private static WcfPublisherService _instance = null;
private IOALogic _logic = null;
private Dictionary<string, IWcfSubscriberContract> _callbacks
= new Dictionary<string, IWcfSubscriberContract>();
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<IWcfSubscriberContract>());
//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();
}
}
}
}
}

WindowsService:

    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;
}
}
}
}

TestForm:

    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 > 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();
}
}
}

TestCallbackClass:

    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; }
}
}
  • vous utilisez nettcpbinding?
  • oui, je suis en utilisant nettcpbinding
  • avez-vous essayé de jouer avec d'autres InstanceContextMode?
  • En fait je suis à la mise en œuvre de la "Liste de publication-souscription Modèle" dans le msdn.microsoft.com/en-us/library/ms752254.aspx... Dans ce cas, le InstanceContextMode doit être PerSession parce que la variable "IWcfSubscriberContract _callback" est défini à l'étendue de classe et doit être une valeur différente pour chaque client. Ce sont séparées par des séances. Aussi, si j'avais le InstanceContextMode plus fin de la Session, la valeur ne serait pas souvenu entre les appels. Par conséquent, il doit être PerSession.
  • Puisque c'est pris directement à partir de la documentation de modèle, je ne comprends pas pourquoi cela ne fonctionne pas. Je dois avoir oublié quelque chose. D'autres idées?
  • Je suis toujours à l'aide de InstanceContextMode.Unique et ConcurrencyMode = ConcurrencyMode.Plusieurs sans problème. Je suis le stockage des callbacks dans simultanées dictionnaire. Il me permet d'informer les clients sur les événements déclenchés par d'autres clients.
  • SalientBrain - merci pour votre aide. Je suis retourné une réécriture de mon service auprès de vos suggestions. Malheureusement, j'ai toujours la même erreur. Le InstanceContextMode est Unique et le ConcurrencyMode est Multiple. J'ai dû me débarrasser de la _callback classe scopped variable et de le remplacer avec un Dictionnaire<string, IWcfSubscriberContract> variable appelée _callbacks. J'ai également eu à ajouter un seul gestionnaire pour ma logique.BarriersChanged de l'événement et de ce gestionnaire j'ai maintenant une boucle par tous les rappels dans le dictionnaire et de faire le rappel des appels.
  • Pour garder les rappels de droite, ma méthode Subscribe prend une chaîne de caractères variable nommée clé que j'ai utiliser comme une clé dans le dictionnaire. Je peux ensuite appeler la Désinscription avec la même clé et retirez pas la bonne entrée de dictionnaire. Je vais devoir revenir en arrière et envelopper le dictionnaire d'accès avec thread-safe trucs, mais tout devrait fonctionner maintenant. L'erreur est toujours présente. La première ligne de l'Abonné(string key) la méthode est: "OperationContext contexte = OperationContext.actuelle;" Après l'exécution de cette ligne de "contexte" est null.
  • Nous sommes de retour à ma question initiale qui était: "quelles sont les raisons de cette méthode retourne null?". D'autres idées? Quelqu'un d'autre a des idées?
  • Montrez votre config
  • SalientBrain, je vais avoir à le saisir dans le formulaire de réponse depuis que j'ai changé le code d'un lot et il ne convient pas ici. Je suis dans le milieu de la nettoyer donc je vais entrer peu de temps. Merci.
  • SalentBrain, veuillez voir mes modifications dans la question d'origine après l' ****
  • Je n'étais pas totalement clair dans le code ci - dessus sont ce que vous créer une instance du type de service dans le client? Ou un proxy WCF/clientchannel? Si vous êtes directement la création d'une instance du type de service, puis l'appel d'une méthode sur elle, il n'y aurait pas OperationContext.
  • Ian vous cloué!!! Je me souviens quand il écrit qu'il se sentait mal. Dès que j'ai regardé en arrière à elle, c'était évident. Maintenant je suis sur la lutte contre les nouvelles dragons. Si vous ajoutez cela comme une réponse, je vais marquer "répondu".

InformationsquelleAutor dtaylor | 2013-03-04