Friday, October 29, 2010

Sending SMS With ASP.NET MVC

Introduction

In this post, I will be sharing the experience I had (integrating SMS) during the development of Delight. With the rising usage of mobile devices, statistics have shown that SMS is the most effective way to communicate, especially for all type of businesses. Honestly, SMS integration to a website if you ask me I would say is easy if you want to stick to just one provider no matter what the future brings. However, this was not the case for Delight, we needed solution that won't require us to rewrite the entire procedure in case we find a better offer by other SMS gateway providers in the future.

The SMS gateway provider I would be using for this post is SMSLive (http://smslive247.com). Before you can use their gateway to send SMS, you must sign-up an account with them and create a sub-account that will be used for sending SMS from your application, the account registration is free.

In other to have a better understand of this tutorial, you need the API documentation (optional for this tutorial) which you can download from their website.

Final view of the application.



















Programming the SMS functionality

Enter the following settings in your web.config AppSettings section.

<add key="SmsUrl" value="http://www.smslive247.com/http/index.aspx"/>
<add key="SmsAccount" value="YOUR-SMSLIVE-EMAIL-ADDRESS"/>
<add key="SubAccount" value="YOUR-SMSLIVE-SUBACCOUNT"/>
<add key="SubAccountPass" value="YOUR-SMSLIVE-SUBACCOUNT-PASSWORD"/>

Now we need a way to access those information in the web.config AppSetings section. Create a new class and name it “ConfigService” and enter the codes below.


public class ConfigService
    {
       public ConfigService(){}

        /// <summary>
        /// Get the SMS gateway url
        /// </summary>
        public string SmsUrl
        {
            get { return getAppSetting(typeof(string), "SmsUrl").ToString(); }
        }

        /// <summary>
        /// Get teh gateway account to use in sending sms message
        /// </summary>
        public string SmsAccount
        {
            get { return getAppSetting(typeof(string), "SmsAccount").ToString(); }
        }

        /// <summary>
        /// Get the sub account to use for the sending of sms
        /// </summary>
        public string SubAccount
        {
            get { return getAppSetting(typeof(string), "SubAccount").ToString(); }
        }

        /// <summary>
        /// Get the sub account password for the sms gateway
        /// </summary>
        public string SubAccountPwd
        {
            get { return getAppSetting(typeof(string), "SubAccountPass").ToString(); }
        }

        private static object getAppSetting(Type expectedType, string key)
        {
            string value = ConfigurationManager.AppSettings[key]; //.Get(key);

            if (value == null)
            {
                throw new Exception(
                    string.Format("The config file does not have the key '{0}' defined in the AppSetting section.", key));
            }

            if (expectedType.Equals(typeof (int)))
            {
                return int.Parse(value);
            }

            if (expectedType.Equals(typeof (string)))
            {
                return value;
            }
            else
                throw new Exception("Type not supported.");
        }
    }

Let’s create a model for our SMS so it will be easier for us to validate it if we want to.

public class SMS
    {
        public string Numbers { get; set; }

        public string SenderId { get; set; }

        public string Message { get; set; }
    }

Remember we are not planning to stick with the current SMS provider for life, at least not when we have a better offer from another provider. This will make our SMS integration a bit lengthy but will pay in the long run.

Create a new class, name "SmsService" and add the following codes.

public class SmsService
    {
        private ConfigService _config;
        private Cache _cache;

        private string sessionId_cahe_key = "SmsSessionId_" + "GetSessionId";

        public SmsService()
        {
            _config = new ConfigService();
            _cache = HttpContext.Current.Cache;
        }

        //Default method for making request to the SMS gateway. This method is not likely to be changed no matter what 
        //SMS gateway provider you want to use in the future.
        private string makeHttpRequest(string url)
        {
            //Initialize the web request
            var webReq = (HttpWebRequest)WebRequest.Create(url);
            webReq.ContentLength = 0;

            webReq.Method = "POST";//We're making a post request. This is the recommended method by the gateway.
            webReq.Timeout = 600000;//Set the timeout for the request

            var webResp = (HttpWebResponse)webReq.GetResponse();

            //Read the response and output it.
            Stream answer = webResp.GetResponseStream();
            StreamReader _answer = new StreamReader(answer);

            string result = _answer.ReadToEnd();

            return result;
        }

        //Instead of providing the subaccount and password in information every request to the SMS gateway, 
        //we use this method to get a session id from the gateway and pass to the service. 
        //This approach is more secure.
        public string Login()
        {
            string result = null;
            //Get the gateway url from the web.config AppSettings section
            string smsUrl = _config.SmsUrl;

            //Form the command for login to send to the gatway. You can download the api documentation 
            //from http://smslive247.com
            string smsCmd = "?cmd=login&owneremail=" + _config.SmsAccount + "&subacct=" + _config.SubAccount +
                            "&subacctpwd=" + _config.SubAccountPwd;

            try
            {
                return result = makeHttpRequest(smsUrl + smsCmd);
            }
            catch (Exception err)
            {
                throw err;
            }
        }

        public string GetSessionId()
        {
            string result = null;//hold the returned message from the request
            bool success = false;//indicate if request is seccessful or not

            //First look for the session id in the cache items, if it does not exist, then trying making a request to the SMS gateway
            //for session id, otherwise get it from the cache
            if (_cache[sessionId_cahe_key] != null)
                result = (string)_cache.Get(sessionId_cahe_key);
            else
            {
                string response = Login();//Call the login method to get the session id from the sms gateway

                string errMsg = null;
                //process and return the response data from the login call in a friendly format
                result = GetResponseMessage(response, out success, out errMsg);

                if (success)//add the session id to the cache if the login request was successful
                {
                    _cache.Add(sessionId_cahe_key, result, null, DateTime.Now.AddHours(2), Cache.NoSlidingExpiration,
                               CacheItemPriority.Normal, null);
                }
            }
            return result;//return the session id
        }

        //Process the response from the sms gateway. By default, the gateway's response is in format below
        //OK: [RESPONSE-Message] -or- ERR: [ERROR NUMBER]: [ERROR DESCRIPTION]
        public string GetResponseMessage(string response, out bool success, out string errMsg)
        {
            //if the response contains 'OK', then the request was successful
            bool isSuccess = response.Substring(0, response.IndexOf(":") + 1).Contains("OK");
            //This holds the code returned from the request. Anything other than 0 means error
            string code = null;
            //This variable holds the description of the error message
            string errDesc = null;

            //get the code for the request
            if (isSuccess)
            {
                code = response.Substring(response.IndexOf(":") + 2);
            }
            else
            {
                code = response.Substring(response.IndexOf(":") + 2, response.LastIndexOf(":") - 1);
                errDesc = response.Substring(response.LastIndexOf(":") + 2);
            }

            success = isSuccess;
            errMsg = errDesc;
            return code;
        }

        public string Send(SMS sms)
        {
            string sessionId = GetSessionId(); //Get the session id
            string smsUrl = _config.SmsUrl; //Get the sms gatway url from the config file

            //Form the command for sending message. You can download the API documentation for full list of commands
            //from http://smslive247.com
            string smsCmd = String.Format("?cmd=sendmsg&sessionid={0}&message={1}&sender={2}" +
                                          "&sendto={3}&msgtype=0", sessionId, sms.Message, sms.SenderId, sms.Numbers);

            bool isSuccess = false;
            string errMsg = null;
            //Send sms message
            string response = makeHttpRequest(smsUrl + smsCmd);

            //Process the response from the gateway
            string code = GetResponseMessage(response, out isSuccess, out errMsg);

            //401 error code indicate invalid Session ID. If the session id is not valid, then delete it from cache and make a 
            //request to get a new session id from the sms gateway
            if (code == "401")
            {
                _cache.Remove(sessionId_cahe_key);//delete the session id from the cache

                sessionId = GetSessionId(); //Get the session id
                smsCmd = String.Format("?cmd=sendmsg&sessionid={0}&message={1}&sender={2}" +
                                          "&sendto={3}&msgtype=0", sessionId, sms.Message, sms.SenderId, sms.Numbers);

                return makeHttpRequest(smsUrl + smsCmd);//resend the sms to the gateway
            }

            return response;
        }
    }

I would be using ASP.NET MVC in the following example, the process to implement this in whatever C# application you want to use it in is the same. If you are working on ASP.NET web-form for example, all you need to do is just substitute the Action method to the control’s method you want to trigger the sending of SMS from.

[HttpPost, ActionName("send-sms")]
        public ActionResult SendSMS(SMS sms)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    bool isSuccess = false;
                    string errMsg = null;
                    string response = _smsService.Send(sms); //Send sms

                    string code = _smsService.GetResponseMessage(response, out isSuccess, out errMsg);

                    if (!isSuccess)
                    {
                        ModelState.AddModelError("", errMsg);
                    }
                    else
                    {
                        ViewData["SuccessMsg"] = "Message was successfully sent.";
                    }
                }
                catch (Exception ex)
                {
                    ModelState.AddModelError("", ex.Message);
                }
            }

            return View(sms);
        }

The HTML

<%=Html.ValidationSummary() %>
<%if (ViewData["SuccessMsg"]!=null){%>
<div class="success"><%=ViewData["SuccessMsg"] %></div>
<%} %>

<form action="<%=Url.Action("send-sms","home") %>" method="post">
<label for="Numbers">Send To</label><br />
<%=Html.TextBox("Numbers") %><br /><br />

<label for="Message">Message</label><br />
<%=Html.TextArea("Message","",new{rows="4",cols="35"}) %><br /><br />

<label for="SenderId">SenderId</label><br />
<%=Html.TextBox("SenderId") %><br /><br />

<input type="submit" value="Send Now" />
</form>

That’s it, we now have a functional website with SMS functionality. You can download the full source code here.

Conclusion

I hope you find this useful. Depending on the kind of Application you’re building, there’s so much more you can do with SMS to make things easier for your users.



5 comments:

Okeowo Aderemi said...

Cool Article i work with PHP and PEAR but currently taking c#, to be frank asp .NET scares me i hope but i know will take it on i hope u continue to post .net tutorials take care

Deji Ajala said...

Nice post. Am flattered that someone did make a blog post using an API I wrote. :) Seriously!

tay said...

It Shows this message
The user does not exist.Invalid GUID.

Neeraj Mehta said...

i am getting error in __smsService
doesn't exist in currentContext

Anonymous said...

can info about the sms be saved in a database? such as the date/timestamp of sms sent, delivery status, error code....

Can the reverse be done programmatically... can a user send an sms that contains data and the information be parsed and stored in a database?

a daily automated sms message goes out to my employees asking for their daily production report. They read the text message and reply to the questions.

Hours TV Inspection?
Number of feet TV Inspected?
Hours Cleaning?
Number of feet Cleaned?

When they reply to the text msg with the data... can it be grabbed and entered into a database?
Another application of this concept could also be used to have employees send in their daily time sheet data.

I would want to capture the sms sender id, date/timestamp, data associated with the sms text,

You think this can be done?

-Michael_In_Oregon





Post a Comment