cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
2778
Views
11
Helpful
8
Replies

Xmpp with .NET

stephan.steiner
Spotlight
Spotlight

Hi

Has anyone gotten Xmpp to work in the .NET world? What library did you use. First one I've tried is S22.xmpp which connects just fine, but I'm not getting anything in terms of messages.

So if anybody tackled this particular problem, I'd love to know which library you ended up using.

Thanks

Stephan

8 Replies 8

ewindgat
Level 5
Level 5

stephan.steiner
Spotlight
Spotlight

thanks.

Unfortunately, I do a pure server (windows service) app without gui.. so I'm not doing BOSH.. but pure XMPP.

I found a library that is working even with pub/sub. it's called matrix, and I've used this information to get started: http://forum.ag-software.net/post/9432;nocount

Unlike the user posting there, I managed to get it going without any problems but I think he didn't use the pubsub address you get from the SystemInformation object.

If you could mention any specific error messages you are receiving that would be good.

I'm not getting any errors anymore I can subscribe for user events of any user and team. I just need to figure how to get a listing of active subscriptions so I don't double subscribe.. but I haven't even touched the surface of what the matrix can do.. I'm sure the pubsub manager has methods (in fact the RequestAllSubscriptions method sounds very promising.. I'll give that a shot shortly).

Hi Stephan

I know its pretty old post, but by any chance can you give any guidance on what libraries you used and if possible any sample code / steps to perform to get started with this XMPP / Pubsub model?

Sorry, I'm pretty new to this XMPP thing, though I do have some .Net exp. Any help would be greatly appreciated.

Regards

Srikanth

I don't have any samples and changing my code into one would be too much effort I'm afraid.

I've used Matrix.NET.. it's payware, but it works reliably (been using it in a productive environment for over a year now without so much as a glitch). I've tried freeware libs but they didn't work out for me so unless you got time to waste, I suggest you buy what you know it's working (I'm not the only one using matrix.net.. you'll find some other devs that have used it in their discussion forum).

Then you wire up some of the event handlers the XmppClient has

xmppClient = new AsyncXmppClient(XmppLogin, server, XmppPassword);

            xmppClient.OnError += XmppClient_OnError;

            xmppClient.OnMessage += XmppClient_OnMessage;

            xmppClient.OnClose += XmppClient_OnClose;

            xmppClient.OnStreamError += XmppClient_OnStreamError;

            xmppClient.OnXmlError += XmppClient_OnXmlError;

OnMessage is the interesting part.. you then need to take e.Message.Value and deserialize that into the Cisco object model (you have to build that manually.. look at the example data in the API guide to build your object model. My code looks like this

private void XmppClient_OnMessage(object sender, MessageEventArgs e)

        {

            try

            {

                Notification not = e.Message.Value.XmlDeserializeFromString<Notification>();

                if (e.Message.Value.Contains("apiErrors"))

                {

                    Notification<ErrorData> errorData = e.Message.Value.XmlDeserializeFromString<Notification<ErrorData>>();

                    CiscoRestApi.Objects.ListOfApiErrors errors = errorData.Data.Data;

                    OnErrorNotification(new ErrorNotificationEventArgs

                    {

                        Errors = errorData.Data.Data,

                        Notification = errorData

                    });

                }

                else

                {

                    switch (not.ObjectType)

                    {

                        case ObjectType.User:

                            Notification<UserData> usrData = e.Message.Value.XmlDeserializeFromString<Notification<UserData>>();

                            OnUserNotification(new UserNotificationEventArgs

                            {

                                Notification = usrData,

                                User = usrData.Data.Data

                            });

                            break;

                        case ObjectType.Queue:

                            Notification<QueueData> queueData = e.Message.Value.XmlDeserializeFromString<Notification<QueueData>>();

                            OnQueueNotification(new QueueNotificationEventArgs

                            {

                                Notification = queueData,

                                Queue = queueData.Data.Data

                            });

                            break;

                        case ObjectType.Team:

                            Notification<TeamData> teamData = e.Message.Value.XmlDeserializeFromString<Notification<TeamData>>();

                            OnTeamNotification(new TeamNotificationEventArgs

                            {

                                Notification = teamData,

                                Team = teamData.Data.Data

                            });

                            break;

                        case ObjectType.Dialog:

                            Notification<DialogData> dialogData = e.Message.Value.XmlDeserializeFromString<Notification<DialogData>>();

                            OnDialogNotification(new DialogNotificationEventargs

                            {

                                Notification = dialogData,

                                Dialog = dialogData.Data.Data

                            });

                            break;

                        case ObjectType.UserDialog:

                            Notification<DialogsData> dialogsData = e.Message.Value.XmlDeserializeFromString<Notification<DialogsData>>();

                            OnUserDialogNotification(new UserDialogNotificationEventArgs

                            {

                                Notification = dialogsData,

                                Dialogs = dialogsData.Data.Data

                            });

                            break;

                        case ObjectType.UserQueue:

                            Notification<QueuesData> queueDatas = e.Message.Value.XmlDeserializeFromString<Notification<QueuesData>>();

                            OnUserQueueNotification(new UserQueueNotificationEventArgs

                            {

                                Notification = queueDatas,

                                Queues = queueDatas.Data.Data

                            });

                            break;

                        case ObjectType.SystemInfo:

                            Notification<SystemInfoData> sysInfoData = e.Message.Value.XmlDeserializeFromString<Notification<SystemInfoData>>();

                            OnSystemInfoNotification(new SystemInfoNotificationEventArgs

                            {

                                Notification = sysInfoData,

                                SystemInfo = sysInfoData.Data.Data

                            });

                            break;

                    }

                }

            }

            catch (Exception x)

            {

                Log("Exception processing message " + e.Message.Value + ": " + x.Message + " at " + e.State, 2);

            }

        }

When you get an OnBindError you know connection has failed and you can call xmppClient.Close(); OnError gives you errors that you should dump just in case. Use the OnBind event to instantiate a new PubSubManager

mgr = new PubSubManager(xmppClient);

Then you can call the methods on mgr. E.g. to get active subscriptions you can use this

Iq data = await mgr.RequestSubscriptionsAsync(pubSubAddress, null, pubSubManagerTimeout).ConfigureAwait(false);

                if (data.Error != null)

                {

                    result.ErrorMessage = data.Error.ToString();

                }

                else

                {

                    var pubSub = data.Element<Matrix.Xmpp.PubSub.PubSub>();

                    result.Result = new List<Subscription>();

                    foreach (var sub in pubSub.Subscriptions.Elements<Matrix.Xmpp.PubSub.Subscription>())

                    {

                        result.Result.Add(sub.ToSubscription());

                    }

                    result.IsSuccess = true;

                }

(ToSubscription is an etension method that turns the subscription into my object model which is a bit easier to work with that the native one.. it just contains the jid (basically presence id), the node and state of the subscription)

And as for subscribing, unbusbscribing, you just need to generate the node path, e,g. to subscribe for a user

string node = "/finesse/api/User/" + userId;

And then you subscribe

private async Task<XmppOperationResult<Subscription>> subscribe(string node, string user, string server)

        {

            XmppOperationResult<Subscription> result = new XmppOperationResult<Subscription>();

            string pubSubAddress = getPubSubAddress(server);

            XmppOperationResult<bool> isSubscribedRes = await isSubscribed(node, server).ConfigureAwait(false);

            if (isSubscribedRes.IsSuccess && isSubscribedRes.Result)

            {

                result.IsSuccess = true;

                Log("We're already subscribed to node " + node + " on server " + server, 3);

                return result;

            }

            else if (!isSubscribedRes.IsSuccess)

            {

                result.IsSuccess = false;

                Log("Unable to determine if we're subscribed to node " + node + " on server " + server, 2);

                return result;

            }

            try

            {

                Iq data = await mgr.SubscribeAsync(pubSubAddress, node, user, pubSubManagerTimeout).ConfigureAwait(false);

                if (data.Type == Matrix.Xmpp.IqType.Result)

                {

                    Log("Successfully subscribed to node " + node, 4);

                    var pubSub = data.Element<Matrix.Xmpp.PubSub.PubSub>();

                    if (pubSub != null)

                    {

                        var sub = pubSub.Element<Matrix.Xmpp.PubSub.Subscription>();

                        result.Result = sub.ToSubscription();

                    }

                    addSubscribedNode(node, activeServerUrl);

                    result.IsSuccess = true;

                }

                else if (data.Type == Matrix.Xmpp.IqType.Error)

                {

                    result.ErrorMessage = data.Error.Value;

                    Log("Subscription to " + node + " failed: " + data.Error, 2);

                }

                else

                {

                    Log("Got an unknown result to subscription attempt for " + node + ": " + data.ToString(), 3);

                    result.ErrorMessage = data.ToString();

                }

            }

            catch (Exception e)

            {

                result.ErrorMessage = Tools.ProcessException(e);

                Log(result.ErrorMessage, 2);

            }

            return result;

        }

Again the interesting bit is calling a method on mgr: SubscribeAsync. As you see there's a lot of plumbing around.. I check if the node is already subscribed so I'm not doing redundant stuff and I keep an internal list of subscriptions just in case.

Unsubscribe works the same, just calling

Iq data = await mgr.UnsubscribeAsync(pubSubAddress, node, user, pubSubManagerTimeout).ConfigureAwait(false);

user by the way is

string.Format("{0}@{1}", XmppLogin, activeServerUrl).ToLower();

and pubSubAddress is

"pubsub." + server

The credentials you use on the xmppClient are credentials of an agent. Create an agent as usual (it needs to be able to log in.. so you need a device and line..), and assign admin rights to it.. then you can subscribe to events from any other user.

If you have a CCX Cluster (as I do), you of course need to manage which server you connect to. I'm using the Finess API to get the SystemInformation data and determine which server is currently online. I'm also using the

To determine whether you can connect, I'm using the Finesse API to get the SystemInformation.

That's about as much as I can give you. If you look for posts of mine in the matrix forums you'll probably find some more code bits. E.g. I implemented async wrappers for opening/closing connections as the pubsubmgr is async and I prefer to go async when there's a way.

Very helpful code snippet.

 

mamdouh.aref
Level 1
Level 1

I have a library working for .Net FCL 2.2

supporting voice inbound and outbound and ECE will be released soon on the same library

you may contact me for more details

maref@istnetworks.com

Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community: