jump to navigation

Developing an XMPP Library in ASP.NET April 5, 2012

Posted by jinzaistudio in ASP.NET 3.5, jinzai-studio.net, Michael T. Blake, programming, Uncategorized, Visual Basic, Visual C#.
trackback

The next few blog entries are an attempt to supplement my resume with a more ‘hands-on’ look at my development process. Disinterested readers can consider themselves forewarned : this is not interesting to anyone that is not interested in the process of programming.

The project that the following entries are going to document is the addition of a real-time chat service to my website. The chat service will use the eXtensible Messaging and Presence Protocol, aka XMPP. XMPP is a ‘protocol’ that is smuggled through the HyperText Transport Protocol (HTTP) using another ‘pseudo-protocol’ called Bidirectional Streams Over Synchronous HTTP, or BOSH. I do not use the term protocol because both BOSH and XMPP are really hiding within HTTP. I do not intend to discuss the differences between binary and character based data, or what constitutes a de facto protocol, or even belabor the fact that the Internet consists of many such partially specified and inconsistently implemented protocols and services. Instead, I will demonstrate how I attempt to implement my own versions of communications, services and applications using Microsoft tools and also by heavy use/abuse of Google and other Internet resources, as well as the documentation that is provided with Microsoft tools, namely Visual Studio.

The project has no real specifications that lie outside the environment that I use to develop code. The website is written in ASP.NET 3.5 and I use VisualBasic exclusively for development of the code behind. However, this project is also being driven by a job listing that I am trying to apply for and that particular company wants C#. That does not confront me at all, since both VB and C# are equally capable of producing .NET code and I cut my eye teeth using x86 assembler, C and C++. I am not afraid of C# and I use VB.NET because that is what my last employer used. They were equally reticent about me saying that I preferred C++, but quickly changed their minds.

Okay, a few last items before I show you the three part framework that is needed to develop such a project. First of all….chat, XMPP and BOSH are add-ons to any website, so there is no baseline support for non ASP.NET componentry per se in .NET Microsoft is not a closed shop, so there are plenty of places where one can take control of things. In the ASP.NET data path, the very best place to start is either the IHttpModule, or the IHttpHandler interface. Since the IHttpModule interface ‘wraps’ the IHttpHandler one without interfering with normal ASPX interactions, that is where I started. N.B. I will likely write an HttpHandler (IHttpHandler) as well, but that is not where you should begin with this type of endeavor. BOSH implementation is a rather complex interaction and there are concerns about how to maintain connection from both the server and the client side. In the case of my website, I am hosted at a server that also hosts many other sites. It would not be a good idea to try to wrestle a lot of processor cycles from other sites. I also have a personal aversion to writing code that puts too much responsibility on the client, or that is otherwise invasive to their resources, or data. Am I jabbing at certain ‘free’ social networking sites? Oh, yeah…I’m doing that very thing right now.

Javascript is the main client side tool for developers that do not want resort to using lot of postbacks to make things interactive and interesting. My website has two very nice examples of ASP.NET User Controls that are implemented entirely in Javascript that require no postbacks whatsoever to play the games that they implement. So, in this project, Javascript is used to create the client side requests. This is a very clunky interaction with ASP.NET The server and client are logically, physically and theoretically separated for security reasons, among other things. The main burden for the developer is to be able to pass information between them in such a way that is does not disturb normal ASP.NET interaction.

The first thing that I did was to create an IHttpModule project in C#, as per the requirement of the fictional client. Microsoft has an example that responds to the two events I am interested in for starting the project, BeginRequest and EndRequest. So, I started with skeleton code similar to that. Another bit of Microsoft example code that came in handy was their code to examine the content of a request.

I have left some of the initial code in there that saves the content to a local file on my computer. The very first goal I had was to be able to capture incoming requests. The module was tested after having been registered using the web.config file. At this point, I had the beginnings of an ASP.NET packet sniffer, although I never bothered with the headers, etc. because I have no interest in them. The module is only supposed to recognize what it suspects is a BOSH module at the time of this blog entry. (I have about 6-8 hours on this project, if such metrics are of interest to the reader.) Since BOSH and XMPP are smuggled in using XML and since XML is one of the most tedious and rigorous of all Internet languages, I simply use the exception mechanism and Microsoft’s XmlDocument class to determine how well formed the XML is and whether it contains a single node named ‘body’. I will do more qualification as the project develops, but I have not yet established a BOSH session, and I am currently writing both the client and the server. Soon, I will test both against other clients and servers and that will be the basis of further work on both sides. There is a more pressing need to get ‘something working’….then work on that.

Here is the code for the BoshModule, which is a DLL that I drop into the website’s bin folder:

using System;
using System.IO;
using System.Web;
using System.Xml;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;

namespace XMPP
{
    public class BoshModule : IHttpModule
    {
        private bool bRelevant = false;

        public BoshModule()
        {
            //
        }

        public String ModuleName
        {
            get { return "BoshModule"; }
        }

        public void Dispose()
        {
            //
        }

        public void Init(HttpApplication theContext)
        {
            theContext.BeginRequest +=
                new EventHandler(BoshModuleBeginRequest);
            theContext.EndRequest +=
                new EventHandler(BoshModuleEndRequest);
        }

        private void BoshModuleBeginRequest(object sender, EventArgs e)
        {
            bRelevant =
                IsBoshRequest(((HttpApplication)sender).Request.InputStream);

        }

        private void BoshModuleEndRequest(object sender, EventArgs e)
        {
            HttpApplication application = (HttpApplication)sender;
            HttpContext context = application.Context;
            string filePath = context.Request.FilePath;
            string fileExtension = VirtualPathUtility.GetExtension(filePath);

            if (fileExtension.Equals(".aspx") && bRelevant)
            {
                context.Response.Write("BoshModule: End of Request");
            }
        }

        private bool IsBoshRequest(Stream theRequestData)
        {
            bool bBoshRequest = false;

            try
            {
                XmlDocument theDocument = new XmlDocument();
                theDocument.Load(theRequestData);
                XmlNodeList theNodeList =
                    theDocument.GetElementsByTagName("body");

                // BOSH contains exactly one node that is named 'body'.

                if (theNodeList.Count == 1)
                {
                    // The number of attributes can be used to determine the
                    // nature of the request without having to traverse the
                    // child nodes. If the code has not already returned,
                    // then this module has some level of interest in this
                    // request. Now, it is time to find out what the nature
                    // of the request is.

                    int numAttributes = theNodeList[0].Attributes.Count;

                    if (numAttributes > 0)
                    {
                        bBoshRequest = true;
                    }
                }

            }

            catch (Exception e)
            {
                // The request does not contain well formed XML,
                // so it is not a BOSH packet, or it is not a well
                // formed BOSH packet. Either way, it is of no
                // interest to this module.

                string theExceptionText = e.Message;
                string theExceptionStackTrace = e.StackTrace;
            }

            //
            return bBoshRequest;
        }

        public void WriteToDiagnosticFile(string theData)
        {
            using (StreamWriter theWriter =
                   new StreamWriter(@"C:/Users/Michael/Documents/UserTemp/test.log",
                   true))
            {
                theWriter.WriteLine(DateTime.Now.ToString() + " - " + theData);
                theWriter.Close();
            }
        }

    }
}

The next blog entry will show the VB.NET code behind that is used to drive the client side.

Advertisements

Comments»

1. Shardaprasad - September 12, 2012

Hi Michael,
Can you share what to do after creating Bosh Module?

jinzaistudio - September 15, 2012

I will address the completion of the BoshModule in an upcoming post. I apologize for leaving this incomplete. XMPP/BOSH can carry most anything you care to put in there, and the BOSH Module is where you would implement your own extensions to the XMPP protocol. Next, I’ll cover chat and instant messaging using BOSH/XMPP. Hopefully, this week sometime. Thanks for your interest and comments.

2. Shardaprasad - September 12, 2012

It is an excellent article provided by you.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: