Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Inherited Message Distributing

  Given a week off of school I found the time to start designing a system that had been thought up in a school class. The idea was simple, a webapp that lets a user reach the widest possible audience by distributing messages across many mediums. One message could be delivered to each recipient as an email, text message, instant message, or phone call to name a few possibilities. With this system, an already overworked teacher could take 30 seconds to send one message that was delivered to each student and parent instantly across multiple mediums. A sports coach could finally reach everyone on the team, without trying to post news on a site that was rarely checked and poorly maintained.
http://www.chalk2me.com/
Difficulty: Intermediate
Time Required: 3-6 hours
Cost: Free
Software: Visual Basic or Visual C# Express Editions
Hardware:
Download: Download
 
Disclaimer: Currently this article is C# only.  If you want it in Visual Basic.Net, please comment and tell us so we can transcode it to VB.

Starting Out:

We thought we had come up with a cool concept, and I knew it wouldn't be that difficult to build. After calling our dev-team into the office I started on it, by myself in my apartment. My goal was to have a single method to send any type of message that would then be picked up by an appropriate thread to deliver the message. As the whole idea here was to create and deliver messages, a logical place to start was a struct to hold our message fields. It's always good to keep other services in mind while you're building your own. I started off with the first 4 fields in any email. This covered message content and we only needed a bit more info to deliver the message. The medium type, along with an identifier field for your address (or screen name etc.), would cover this. Just in case a service we end up using needs a second identifier, I added one more. Check it out:

public struct ctMessage
{
    public ctMessage(string sendToUser, string fromUser, string subj, string msg, string

    mediumType, string mediumArg1, string mediumArg)
    {
        this.toUser = sendToUser;
        this.fromUser = fromUser;
        this.subject = subj;
        this.message = msg;
        this.mediumType = mediumType;
        this.mediumArg1 = mediumArg1;
        this.mediumArg2 = mediumArg2;
    }

    public string toUser; //name of recipient
    public string fromUser; //name of sender
    public string subject;
    public string message;
    public string mediumType; //which node should deliver this
    public string mediumArg1; //varies, to identify the recipient
    public string mediumArg2; //varies, to identify the recipient
}

Once we had a message designed I, of course, wanted to be able to send one! Eventually I wanted a bunch of different types of messages being sent, so a solid base class would save a ton of time later. Although all of the messaging services, or ‘nodes' would undoubtedly send the messages completely different, they would all need to run in a similar thread that sent messages coming from a single location. By doing a good job writing an abstract base class, we could add new services by only overriding the 'send' method later.

This abstract class would have a field identifying the type of messages it will handle, and call an external send method whenever messages of that type existed. A continuous loop to poll for messages, given a modest polling frequency would do the trick. Notice the protected methods and fields that we'll want to override.

public abstract class ctNode
{
    public ctNode()
    {
        this.maxQueueSize = 100; //Set the size according to how long it will take to reach the Nth message
        this.msgQueue = new Queue(maxQueueSize);
        this.msPauseAfterRun = 10000; //If using a DB, polling it with no pause b/w queries is an unnecessary load
        this.runnerThread = new Thread(new ThreadStart(this.run));
    }

    private Thread runnerThread;
    protected int msPauseAfterRun;
    protected Queue msgQueue;
    public int maxQueueSize;

    void run()
    {
        while (true)
        {
            while (this.msgQueue.Count > 0)
            {
                //pop a message and send it
                ctMessage ctm = (ctMessage)msgQueue.Dequeue();

                try
                {
                    sendSingleMessage(ctm);
                }
                catch (Exception e)
                {
                    //Write a more detailed error log here
                    Console.writeLine("the message could not be sent!" + e.toString());
                }
            }

            //get new messages
            ctNode ctn = this;
            ctMessage[] newMessages = messageSender.getMessages(ref ctn, getRoomInQueue());

            //Wait some time before checking for more messages!
            if (newMessages.Length == 0)
                Thread.Sleep(msPauseAfterRun);
            else
                this.EnqueueMessages(newMessages);
        }
    }

    public virtual void EnqueueMessages(ctMessage[] messagesToSend)
    {
        int roomInQueue = maxQueueSize - msgQueue.Count;

        if (messagesToSend.Length > roomInQueue)
            throw new Exception("Too many Messages have been inserted");

        for (int i = 0; i < messagesToSend.Length; i++)
        {
            msgQueue.Enqueue(messagesToSend[i]);
        }
    }

    public virtual void EnqueueMessages(ctMessage messageToSend)
    {
        ctMessage[] ctm = new ctMessage[1];
        ctm[0] = messageToSend;
        this.EnqueueMessages(ctm);
    }

    protected virtual void sendSingleMessage(ctMessage ctm)
    {
        //code to send an individual message
    }

    public void startThread()
    {
        runnerThread.Name = this.nodeType;
        runnerThread.Start();
    }

    protected string nodeType;

    public string getNodeType()
    {
        return this.nodeType;
    }
}

You might have noticed the big thing missing from these classes, a place to store, and retrieve messages! I initially put our message storage into an external static class. This made them centralized, easily accessible from any other objects that might need to access them, simple to ensure thread safety, and gave us room to move to a smarter mechanism later (or database. Notice the simplicity:

public static class messageSender
{
    private static List<ctMessage> messagesToSend = new List<ctMessage>();

    public static ctMessage[] getMessages(ref ctNode nodeRef, int numberOfMessages)
    {
        //We'll do this in a database later, but for now this works similarly
        List<ctMessage> returnMessages = new List<ctMessage>();

        lock (messagesToSend)
            for (int i = 0; i < messagesToSend.Count; i++)
                if (messagesToSend[i].mediumArgs == nodeRef.getNodeType())
                {
                    returnMessages.Add(messagesToSend[i]);
                    messagesToSend.RemoveAt(i);
                    i--;
                }

        return returnMessages.ToArray();
    }

    public static void sendMessage(ctMessage message)
    {
        lock (messagesToSend)
            messagesToSend.Add(message);
    }
}

Now that the groundwork was done, I grabbed some eye drops and an energy drink to refresh for the best part, function! I started simple with an email node, and if you've played with email before in .net, you've definitely seen and loved the SmtpClient class in the System.Net.Mail Namespace. If you don't already have a local SMTP client set up, you can easily use a Gmail account as an SMTP server. Check out the following implementation, notice we only had to set the node type, initialize the SmtpClient and override the send method. Send a message through our message sender, and watch the node pick up the message and deliver it. Inheritance rocks!

ctMessage ctm = new ctMessge("Friend", "Developer", "testing", "My first message", "email", "yourEmail@yourDomain.com", "");
messageSender.sendMessage(ctm);

public class ctNodeEmail : ctNode
{
    public ctNodeEmail() : base()
    {
        this.nodeType = "email";

        //
        //SET UP SMTP CLIENT
        //

        //GMAIL SERVER
        this.mSmtpClient = new SmtpClient("gmail.com/mail", 25);
        this.mSmtpClient.Host = "smtp.gmail.com";
        this.mSmtpClient.Port = 25;
        this.mSmtpClient.EnableSsl = true;
        this.mSmtpClient.Credentials = new System.Net.NetworkCredential("YOURADDRESS@gmail.com", "YOUR_PASSWORD");

        //LOCAL SERVER
        //this.mSmtpClient = new SmtpClient("localhost", 25);
    }

    SmtpClient mSmtpClient;

    protected override void sendSingleMessage(ctMessage ctm)
    {
        MailMessage msgMail = new MailMessage(new MailAddress(ctm.fromUser + "@ChalkTalkNow.com"), new MailAddress(ctm.mediumArgs));
        msgMail.Subject = ctm.subject;
        string msg = ctm.message;
        msgMail.Body = msg;

        // Send the mail message
        mSmtpClient.Send(msgMail);
    }
}

After writing this so quickly I wanted something a bit more than email, and knew text messages were only a step away. It's no secret that all major cell companies give your phone an email address, you just need to append the proper domain to your number. Building off of our email node, we used the first mediumArg to hold a phone number, and put the carrier into the second mediumArg.

public class ctNodeTextMessage : ctNode
{
    public ctNodeTextMessage() : base()
    {
        this.nodeType = "textmessage";

        //
        //SET UP SMTP CLIENT
        //
        this.mSmtpClient = new SmtpClient("gmail.com/mail", 25);
        this.mSmtpClient.Host = "smtp.gmail.com";
        this.mSmtpClient.Port = 25;
        this.mSmtpClient.EnableSsl = true;
        this.mSmtpClient.Credentials = new System.Net.NetworkCredential("GMAIL@gmail.com", "PASSWORD");

    }
    SmtpClient mSmtpClient;

    private string getEmailAddress(string phoneNumber, string provider)
    {
        switch (provider)
        {
            case "t-mobile":
                return phoneNumber + "@tmomail.net";
            case "virginmobile":
                return phoneNumber + "@vmobl.com";
            case "cingular":
                return phoneNumber + "@cingularme.com";
            case "att":
                return phoneNumber + "@cingularme.com";
            case "sprint":
                return phoneNumber + "@messaging.sprintpcs.com";
            case "verizon":
                return phoneNumber + "@vtext.com";
            case "nextel":
                return phoneNumber + "@messaging.nextel.com";
            default:
                //assume cingular/att is the most popular
                return phoneNumber + "@cingularme.com";
        }
    }

    protected override void sendSingleMessage(ctMessage ctm)
    {
        //send a single message
        string emailAddress = getEmailAddress(ctm.mediumArg1, ctm.mediumArg2);

        MailMessage msgMail = new MailMessage(new MailAddress(ctm.fromUser + "@chalktalk.net", ctm.fromUser), new MailAddress(emailAddress));
        msgMail.Subject = ctm.subject;
        msgMail.Body = ctm.message;
        sendEmail(msgMail);
    }

    private void sendEmail(MailMessage msgMail)
    {
        // Send the mail message
        this.mSmtpClient.Send(msgMail);
    }
}

Now to test this out, just like we sent the email we'll send a text. Cool!

ctMessage ctm = new ctMessge("Friend", "Developer", "testing", "hello world via text", "textmessage", "#########", "verizon");
messageSender.sendMessage(ctm);

Conclusion:

When you're working on a project with a small team, it's especially important to build a good foundation like this so you can focus on easily added functionality without getting bogged down in complexity. This portion of the project was written over the course of a week and later on allowed us to focus almost exclusively on adding new services like Instant Messengers and interactive phone calling. Having functionality so quickly was crucial, along with a UI built by my brother, in getting the attention and support of others to build a business around this.

Next Steps:

  • Build a UI to manage content and run your messaging!
  • Rewrite your messageSender class to store messages in a database. This will make your app much more extensible, and you can save a record of the messages sent in an ‘outbox'.
  • Strongly type all textual identifiers in enumerations to avoid any frustrating mistakes.
  • Find an SDK for your favorite messenger, and build a node for it
  • Join our team and continue to build with us!

Tags:

Follow the Discussion

  • BobBob

    Yes a VB.net version would be nice.

  • Clint RutkasClint I'm a "developer"

    @Bob Thanks, I will get to this then.

  • jalaljalal

    cool can you trancode it to vb language

  • GCGC

    Hi Robert,

    An alternative would be to have a base abstract "Message" class and a sub-type for each message type, e.g. TextMessage, EmailMessage etc. To create a message you just call new TextMessage(args) and you have your TextMessage object.

    The Message base class defines a method "send()". Each message sub-class should know how to send itself.

    To send your messages all you have to do is go through your queue of Message objects calling "send()" on each.

    I'm curious as to why you chose to sub-class the sender rather than the message, as "send()" seems like something a message should be able to do?

    Cheers,

    GC

  • RobRob

    GC,

    You bring up a couple of interesting points, that are not well addressed in this piece.  For the simple examples shown, you could certainly encapsulate sending functionality within the message struct, with perhaps a statically maintained connection.

    When you're designing a web app with a lot done behind the scenes it's often best to decouple the interface and the processing.  For the larger project here this meant an interface needed a message struct solely to hold fields.  A second server, running the nodes might be actually doing the sending.  This design allows you to not expose the node overhead to the UI developers that won't be it anyways.

    The second point to consider is that a node may require a persistent singleton connection that must talk to another server.  In this case it is easier to maintain sending in a separate class/thread that always runs.

    -Rob

  • OronOron

    Yes Please give a VB version!!!

  • mgettamgetta

    hey, the idea is cool but im not farmiliar with C# PLS CAN U TRASCODE IN VB

  • Clint RutkasClint I'm a "developer"

    @rmehta looking into this

  • rmehtarmehta

    I could not find the downloable code on codeplex.

  • Clint RutkasClint I'm a "developer"

    @Oron:  Working on it, just have other things on my plate.

    http://converter.telerik.com/ can do most of the heavy lifting.

  • Ritesh MehtaRitesh Mehta

    I could not find the downloable code on codeplex.

  • Ritesh MehtaRitesh Mehta

    Just wanted to followup if you manged to get the code. I could not find the code at the downloadable link

  • Clint RutkasClint I'm a "developer"

    @rmehta working on getting it back up.

  • OronOron

    Hey thanks, I know how it gets!!!

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.