Not logged in. · Lost password · Register
Forum: MatriX and XmppDotNet RSS
Avatar
asiebersma-hbs #1
Member since Jun 2017 · 3 posts
Group memberships: Members
Show profile · Link to this post
Subject: Connection fails to receive XML from Worker Thread
We have an application which attempts to initialize a Matrix XMPP listener in a worker thread. When we do this, the client's OnSendXml event fires, but other events do not (in particular, OnReceiveXML and OnLogin).

Initializing the client outside of the worker thread functions as expected, but won't work in production given our overall architecture (we don't know the Password and Username until we are already in the worker thread).

For diagnostic purposes, I've created a minimal application that demonstrates the issue.

From a standard Windows Form Application template (with the MatriX v2.1.0.2 Nuget package installed) , this code works (breakpoints in OnReceiveXml, OnSendXml, and OnLogin are all hit):

  1. public partial class Form1 : Form {
  2.     public Form1() {
  3.         InitializeComponent();
  4.     }
  5.  
  6.     private void OnReceiveXml(object sender, Matrix.TextEventArgs e) {
  7.         Console.WriteLine("ReceiveXml");
  8.     }
  9.  
  10.     private void OnSendXml(object sender, Matrix.TextEventArgs e) {
  11.         Console.WriteLine("SendXml");
  12.     }
  13.  
  14.     private void OnLogin(object sender, Matrix.EventArgs e) {
  15.         Console.WriteLine("Login");
  16.     }
  17.  
  18.     private void button1_Click(object sender, System.EventArgs e) {
  19.             XmppClient xmppClient = new XmppClient();
  20.             Matrix.License.LicenseManager.SetLicense(System.Configuration.ConfigurationManager.AppSettings["MatrixLicenseKey"].ToString());
  21.             xmppClient = new XmppClient();
  22.  
  23.             xmppClient.Transport = Matrix.Net.Transport.Bosh;
  24.             xmppClient.PreferredSsoSaslMechanism = Matrix.Xmpp.Sasl.SaslMechanism.Plain;
  25.             xmppClient.AutoPresence = true;
  26.             Uri originalUri = new Uri("http://xxxxx/finesse/api");
  27.             xmppClient.Uri = new System.Uri("https://" + originalUri.Host + ":7443/http-bind/");
  28.             xmppClient.Password = "xxxxx";
  29.             xmppClient.Username = "xxxxx";
  30.             xmppClient.Port = 7443;
  31.             xmppClient.XmppDomain = originalUri.Host;
  32.  
  33.             xmppClient.OnReceiveXml += new System.EventHandler<Matrix.TextEventArgs>(OnReceiveXml);
  34.             xmppClient.OnSendXml += new System.EventHandler<Matrix.TextEventArgs>(OnSendXml);
  35.             xmppClient.OnLogin += new System.EventHandler<Matrix.EventArgs>(OnLogin);
  36.  
  37.             xmppClient.Open();
  38.     }
  39. }

But this code fails (breakpoints in OnReceiveXml and OnLogin are never hit):

  1. public partial class Form1 : Form {
  2.     public Form1() {
  3.         InitializeComponent();
  4.     }
  5.  
  6.     private void OnReceiveXml(object sender, Matrix.TextEventArgs e) {
  7.         Console.WriteLine("ReceiveXml");
  8.     }
  9.  
  10.     private void OnSendXml(object sender, Matrix.TextEventArgs e) {
  11.         Console.WriteLine("SendXml");
  12.     }
  13.  
  14.     private void OnLogin(object sender, Matrix.EventArgs e) {
  15.         Console.WriteLine("Login");
  16.     }
  17.  
  18.     private void button1_Click(object sender, System.EventArgs e) {
  19.         System.Threading.ThreadPool.QueueUserWorkItem((o) => {
  20.             XmppClient xmppClient = new XmppClient();
  21.             Matrix.License.LicenseManager.SetLicense(System.Configuration.ConfigurationManager.AppSettings["MatrixLicenseKey"].ToString());
  22.             xmppClient = new XmppClient();
  23.  
  24.             xmppClient.Transport = Matrix.Net.Transport.Bosh;
  25.             xmppClient.PreferredSsoSaslMechanism = Matrix.Xmpp.Sasl.SaslMechanism.Plain;
  26.             xmppClient.AutoPresence = true;
  27.             Uri originalUri = new Uri("http://xxxxx/finesse/api");
  28.             xmppClient.Uri = new System.Uri("https://" + originalUri.Host + ":7443/http-bind/");
  29.             xmppClient.Password = "xxxxx";
  30.             xmppClient.Username = "xxxxx";
  31.             xmppClient.Port = 7443;
  32.             xmppClient.XmppDomain = originalUri.Host;
  33.  
  34.             xmppClient.OnReceiveXml += new System.EventHandler<Matrix.TextEventArgs>(OnReceiveXml);
  35.             xmppClient.OnSendXml += new System.EventHandler<Matrix.TextEventArgs>(OnSendXml);
  36.             xmppClient.OnLogin += new System.EventHandler<Matrix.EventArgs>(OnLogin);
  37.  
  38.             xmppClient.Open();
  39.         }, null);
  40.     }
  41. }

What would cause the xmppClient to fail in this scenario? What can we do to work around this issue?
This post was edited on 2017-06-26, 23:05 by Alex.
Avatar
Alex #2
Member since Feb 2003 · 4449 posts · Location: Germany
Group memberships: Administrators, Members
Show profile · Link to this post
the call to Open is async in MatriX. I see no reason why you should execute this in a Threadpool. MatriX creates its own threads anyway.

Why are you creating a new XmppClient twice?

Have you tried to declare the xmppClient object outside of QueueUserWorkItem?
Avatar
asiebersma-hbs #3
Member since Jun 2017 · 3 posts
Group memberships: Members
Show profile · Link to this post
Quote by Alex:
the call to Open is async in MatriX. I see no reason why you should execute this in a Threadpool. MatriX creates its own threads anyway.

Our production app is much more complex. It uses various patterns to abstract states and commands, and runs code to execute commands and transition states in worker threads. So you have a button, which generates a login command object. That login command object has a method that run in a worker thread, which queries the database for login information/URLs/etc. and constructs the xmppClient with the results.

In the production application, eliminating the worker thread isn't an option. If there is another threading object that works, that would be possible... But I've tried both threads and tasks and run into the same results.

The attached application doesn't serve a practical purpose. It's goal is to be as small as possible for troubleshooting purposes.

If running the Matrix xmpp client in a Threadpool is actively not supported/not intended, that would be useful info.

Quote by Alex:
Why are you creating a new XmppClient twice?

No particular reason. I refactored the code to eliminate the duplicate instantiation, and still encountered the issue.

Quote by Alex:
Have you tried to declare the xmppClient object outside of QueueUserWorkItem?

I just tried this, and had no luck. Code after these two suggested changes:

  1.     public partial class Form1 : Form {
  2.         XmppClient xmppClient = new XmppClient();
  3.  
  4.         public Form1() {
  5.             InitializeComponent();
  6.         }
  7.  
  8.         private void OnReceiveXml(object sender, Matrix.TextEventArgs e) {
  9.             Console.WriteLine("ReceiveXml");
  10.         }
  11.  
  12.         private void OnSendXml(object sender, Matrix.TextEventArgs e) {
  13.             Console.WriteLine("SendXml");
  14.         }
  15.  
  16.         private void OnLogin(object sender, Matrix.EventArgs e) {
  17.             Console.WriteLine("Login");
  18.         }
  19.  
  20.         private void button1_Click(object sender, System.EventArgs e) {
  21.             Matrix.License.LicenseManager.SetLicense(System.Configuration.ConfigurationManager.AppSettings["MatrixLicenseKey"].ToString());
  22.            
  23.  
  24.             System.Threading.ThreadPool.QueueUserWorkItem((o) => {
  25.                 xmppClient.Transport = Matrix.Net.Transport.Bosh;
  26.                 xmppClient.PreferredSsoSaslMechanism = Matrix.Xmpp.Sasl.SaslMechanism.Plain;
  27.                 xmppClient.AutoPresence = true;
  28.                 Uri originalUri = new Uri("http://xxxxx/finesse/api");
  29.                 xmppClient.Uri = new System.Uri("https://" + originalUri.Host + ":7443/http-bind/");
  30.                 xmppClient.Password = "xxxxx";
  31.                 xmppClient.Username = "xxxxx";
  32.                 xmppClient.Port = 7443;
  33.                 xmppClient.XmppDomain = originalUri.Host;
  34.  
  35.                 xmppClient.OnReceiveXml += new System.EventHandler<Matrix.TextEventArgs>(OnReceiveXml);
  36.                 xmppClient.OnSendXml += new System.EventHandler<Matrix.TextEventArgs>(OnSendXml);
  37.                 xmppClient.OnLogin += new System.EventHandler<Matrix.EventArgs>(OnLogin);
  38.  
  39.                 xmppClient.Open();
  40.             }, null);
  41.         }
  42.     }
Avatar
Alex #4
Member since Feb 2003 · 4449 posts · Location: Germany
Group memberships: Administrators, Members
Show profile · Link to this post
Have you tried to disable AutoInvoke?
Avatar
Alex #5
Member since Feb 2003 · 4449 posts · Location: Germany
Group memberships: Administrators, Members
Show profile · Link to this post
I tried your code.
As suggested setting AutoInvoke to false solves your problem.

MatriX tries to find a Dispatcher in your GUI automatically, which cannot work when you execute it not on a UI thread.
So just make sure that AutoInvoke is false.

You also can set your dispatcher manual if you want MariX to invoke all the events for you.

Alex
This post was edited on 2017-06-27, 18:05 by Alex.
Avatar
asiebersma-hbs #6
Member since Jun 2017 · 3 posts
Group memberships: Members
Show profile · Link to this post
Perfect, thank you Alex! This solved the issue in both my test code and production.

Thank you for the explanation.
Close Smaller – Larger + Reply to this post:
Verification code: VeriCode Please enter the word from the image into the text field below. (Type the letters only, lower case is okay.)
Smileys: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Special characters: