Overview of Mobile Messaging Development

Applies to: SharePoint Foundation 2010

This topic provides an overview of adding mobile messaging functionality to a Microsoft SharePoint Foundation development project using the mobile messaging APIs of the SharePoint Foundation Software Development Kit (SDK). These APIs can be usefully divided into two broad groups: those that support Short Message Service (SMS) messaging (also called "texting") using the Office Mobile Service (OMS) communication protocol and those that enable you to build support for other communication or message structure protocols. In most development scenarios, the sender of the messages is the SharePoint Foundation Web application as opposed to a particular user, so the SharePoint Foundation deployment will need to have an account with a mobile messaging service provider (MSP) company that supports the communication protocol that your solution uses.

Office Mobile Service (OMS) Protocol is a communication protocol that provides an implementation of the SMS and Multimedia Message Service (MMS) message structure protocols. OMS requires the SOAP protocol for Web service access. The OMS-supporting APIs discussed in OMS-SMS Messaging Solutions below are designed for SMS messaging. Any classes or members you find in the Microsoft.SharePoint.MobileMessage namespace with "MMS" in their name, or which only make sense in the context of MMS messaging, are for internal use only and should not be called from your code. To develop messaging solutions that do not use OMS as the communication protocol or that use OMS for MMS messages, use the more abstract level of APIs discussed in Developing for Other Protocols below.

OMS-SMS Messaging Solutions

SharePoint Foundation provides APIs that do all the OMS Web Method calling, and all of the XML parsing and writing, for you. Your code simply calls the APIs in familiar object-oriented syntax.

Creating an MSP Account for a Web Application

Each SharePoint Foundation Web application, including the Central Administration Web application, can have an account with an MSP. Normally, these accounts are set by a farm administrator in the Application Management portion of the Central Administration application. However, you can programmatically create an account and assign it to a Web application. First, call a SPMobileMessagingAccount() constructor that does not require an SPMobileMessageServiceProvider parameter. Then call the UpdateSmsAccount(SPMobileMessagingAccount) method to assign the account to a Web application. In the following snippet, webApp is a reference to an SPWebApplication object. (See Getting References to Sites, Web Applications, and Other Key Objects for information about how to get a reference to such an object.) The snippet assumes that the file has using statements for Microsoft.SharePoint and System.Security. Note that the call to UpdateSmsAccount(SPMobileMessagingAccount) is passed as part of an anonymous delegate to the RunWithElevatedPrivileges(SPSecurity.CodeToRunElevated) method.

SecureString password = new SecureString();
password.AppendChar(‘a’);
password.AppendChar(‘Z’);
password.AppendChar(‘3’);
password.AppendChar(‘&’);

SPMobileMessagingAccount account = new SPMobileMessagingAccount("Contoso Messaging",
                                                                "https://contoso.com/services/mobilemessages",
                                                                 "BobG",
                                                                 password);

SPSecurity.RunWithElevatedPrivileges(delegate() {webApp.UpdateSmsAccount(account);
                                                 webApp.Update();});
Dim password As New SecureString()
        password.AppendChar("a")
        password.AppendChar("z")
        password.AppendChar("3")
        password.AppendChar("&")

        Dim account As New SPMobileMessagingAccount("Contoso Messaging", "https://contoso.com/services/mobilemessages", "BobG", password)


        SPSecurity.RunWithElevatedPrivileges(Sub()
                                                 webApp.UpdateSmsAccount(account)
                                                 webApp.Update()
                                             End Sub)

After the Web application has been assigned an account with the MSP, your code can thereafter use the OutboundSmsServiceAccount property as a reference to the Web application’s account object.

Creating a Web Service Object

When you have an SPMobileMessagingAccount, your code can use it to create an SPMobileMessageWebService object that contains the methods for sending SMS messages. We recommend that whenever you obtain a reference to a persisted SPMobileMessagingAccount object, you always verify that it is not null and that its IsValidAccount() property is true. The following snippet illustrates how to create a Web service object. webApp is a reference to an SPWebApplication object.

SPMobileMessagingAccount account = webApp.OutboundSmsServiceAccount;
if (account == null || !account.IsValidAccount())
{
    throw new SPException("The account passed in is invalid.");
}
else
{
    SPMobileMessageWebService messagingWebService = new SPMobileMessageWebService(account);
}
Dim account As SPMobileMessagingAccount = webApp.OutboundSmsServiceAccount
If account Is Nothing OrElse (Not account.IsValidAccount()) Then
    Throw New SPException("The account passed in is invalid.")
Else
    Dim messagingWebService As New SPMobileMessageWebService(account)
End If

Building and Sending a Mobile Message

The next two critical tasks are building and sending the message.

Building a Message

With a SPMobileMessageWebService object your code can call the service’s OMS Web Methods by using the methods of the object as proxies. The most important of these, of course, is the SendMessage(String) method. However, before you can call it, your code must build the message. There are three methods for doing this.

  • Your code can call the static BuildSmsMessage(SPMobileMessagingAccount, String, String) method and pass it parameters for the sender’s account, a recipient, and the text for the message. This is the simplest, but least flexible way.

  • Your code can call one of the overloads of SetTextContent(). This would require you to first construct the SPMobileMessageSmsBuilder and add recipients with calls of the AddRecipient(String) method and also to convert the message from the SPMobileSmsMessage object that SetTextContent() creates to the proper message XML of the OMS protocol. But this way of building the message gives you the option to have multiple recipients. It also enables you to set a lower limit on the number of child pages than the limit that is imposed by the service provider.(ContentParts) into which the message is split if the message text exceeds the character limit imposed by the service.

  • Your code can create a messaging building transaction. Such a transaction consists of the following:

    1. A call of StartTextMessage()

    2. One or more calls of AddChunk(String)

    3. A call of one of the overloads of EndTextMessage()

    This way of building the message gives you all the options, and all the complications, as the preceding way, but also gives you greater control over how the message is split into pages as well as additional options, such as the option to add page numbers.

Regardless of the method used, if a message exceeds the service provider’s limit on the number of characters, the message construction algorithm will attempt to divide the message into multiple messages by splitting the message between "chunks" of text. A chunk of text is a run of characters that should stay together in a single message, if possible. This will make the resulting series of messages more coherent than if the parent message was divided into equal, but arbitrarily divided, parts. If a specific chunk itself exceeds the character limit, it will be split anyway. Only the third method of building a message enables your code to have some control over how the message is split into chunks. The following snippet illustrates the third method. Note the following about this example:

  • account is a reference to an SPMobileMessagingAccount object.

  • Although there is only one call of AddRecipient(String), you can call it multiple times to send the same message to multiple recipients, up to the limit imposed by the MSP.

  • SplitLongMessage is defined in the next code block below.

  • message is a String object that contains the message.

  • When the message building transaction is complete, the SPMobileMessageSmsBuilder object holds the message in its Message property.

SPMobileMessageSmsBuilder smsBuilder = new SPMobileMessageSmsBuilder(account);
smsBuilder.AddRecipient(mobile_telephone_number);

// Begin the message building transaction
smsBuilder.StartTextMessage();

// Add the message text, split as needed into chunks.
List<StringBuilder> messageParts = SplitLongMessage(message)
foreach (StringBuilder chunk in messageParts)
{
    smsBuilder.AddChunk(chunk.ToString());
}

// Finish the transaction
smsBuilder.EndTextMessage();

// At this point, the smsBuilder.Message property holds the message as an SPMobileSmsMessage object.
Dim smsBuilder As New SPMobileMessageSmsBuilder(account)
smsBuilder.AddRecipient(mobile_telephone_number)

' Begin the message building transaction
smsBuilder.StartTextMessage()

' Add the message text, split as needed into chunks.
Dim messageParts As List(Of StringBuilder) = SplitLongMessage(message)
For Each chunk As StringBuilder In messageParts
    smsBuilder.AddChunk(chunk.ToString())
Next

' Finish the transaction
smsBuilder.EndTextMessage()

' At this point, the smsBuilder.Message property holds the message as an SPMobileSmsMessage object

The SplitLongMessage method implements a simple algorithm to ensure that no chunk of the message exceeds the SMS limit of 133 (single-byte) characters for each chunk of a concatenated SMS message, sometimes called a "long SMS message". Moreover, it ensures that splits always come at white space, so no word is split between message parts. A more complex algorithm would be needed if your mobile messaging solution cannot assume that all the characters in the message will be single-byte.

public static List<StringBuilder> SplitLongMessage(String message)
{
    // Split the original message at white space.
    String[] words = message.Split(null);

    List<StringBuilder> chunks = new List<StringBuilder>();
    StringBuilder latestChunk = new StringBuilder(132);

    // Reconstruct the message in chunks of up to 133 characters.
    foreach (String word in words)
    {
        if (word.Length + latestChunk.Length <= 132) //Not 133 because a space will be added
        {
            latestChunk.Append(word + " "); // Add back the white space
        }
        else
        {
            // Add a copy of the chunk to the list
            chunks.Add(new StringBuilder(latestChunk.ToString()));

            // Empty out latest chunk so the next one can be started
            latestChunk.Remove(0, latestChunk.Length);

            // The word that exceeded the limit becomes the first word of the next chunk
            latestChunk.Append(word + " ");
        }
    }

    // Add the last short chunk
    if (latestChunk.Length > 0)
    {
        chunks.Add(latestChunk);
    }

    return chunks;
}
Public Shared Function SplitLongMessage(ByVal message As String) As List(Of StringBuilder)
    ' Split the original message at white space.
    Dim words() As String = message.Split(Nothing)

    Dim chunks As New List(Of StringBuilder)()
    Dim latestChunk As New StringBuilder(132)

    ' Reconstruct the message in chunks of up to 133 characters.
    For Each word As String In words
        If word.Length + latestChunk.Length <= 132 Then 'Not 133 because a space will be added
            latestChunk.Append(word & " ") ' Add back the white space
        Else
            ' Add a copy of the chunk to the list
            chunks.Add(New StringBuilder(latestChunk.ToString()))

            ' Empty out latest chunk so the next one can be started
            latestChunk.Remove(0, latestChunk.Length)

            ' The word that exceeded the limit becomes the first word of the next chunk
            latestChunk.Append(word & " ")
        End If
    Next word

    ' Add the last short chunk
    If latestChunk.Length > 0 Then
        chunks.Add(latestChunk)
    End If

    Return chunks
End Function

Whether you built the SPMobileSmsMessage object (referenced in the SPMobileMessageBuilder.Message property) with a call of SetTextContent() or by using a message building transaction, your code must convert that object into the proper OMS format message XML. This is done by a call of the GetMessageXml() method. This additional XML writing step is not required if you build your message by using a call of the BuildSmsMessage(SPMobileMessagingAccount, String, String) method, because it returns the message XML.

String messageXml = smsBuilder.GetMessageXml();
Dim messageXml As String = smsBuilder.GetMessageXml()

Sending a Message

A message is sent by passing the complete, OMS-compliant message XML to the SendMessage(String) method of an SPMobileMessageWebService object. See Creating a Web Service Object above for information about how to create such an object. In the following snippet, messagingWebService is an SPMobileMessageWebService object and messageXml is the complete OMS-compliant message.

SPMobileMessageDeliveryReport report = messagingWebService.SendMessage(messageXml);
Dim report As SPMobileMessageDeliveryReport = messagingWebService.SendMessage(messageXml)

The report that is returned by SendMessage(String) contains information about whether the message was successfully sent and, if not, why it was not. We recommend that you include code that processes the report, logs successful messages, and responds to failures. For information about the structure of the report, see SPMobileMessageDeliveryReport.

Sending Batches of Messages

If your solution uses batch sending, your code will need to store the messages that are created between batch jobs in some kind of queue structure that can be flushed when the batch is sent, such as List<T><SPMobileSmsMessage>. The batch job begins with the creation of an SPMobileMessageBatchPackage object to which each message object is added. Then the package is passed to the BatchSendMessages(SPMobileMessageBatchPackage) method.

In the snippet below, messageCollection is a List<T><SPMobileSmsMessage> object and messagingWebService is an SPMobileMessageWebService object. See Creating a Web Service Object above for information about how to create such an object.

SPMobileMessageBatchPackage package = new SPMobileMessageBatchPackage();

foreach (SPMobileSmsMessage message in messageCollection)
{
    package.AddMessage(message);
}

List<SPMobileMessageDeliveryReport> reports = messagingWebService.BatchSendMessages(package);
Dim package As New SPMobileMessageBatchPackage()

For Each message As SPMobileSmsMessage In messageCollection
    package.AddMessage(message)
Next message

Dim reports As List(Of SPMobileMessageDeliveryReport) = messagingWebService.BatchSendMessages(package)

Note that there is no need to explicitly convert the SPMobileSmsMessage objects that are in the package to OMS-compliant XML messages. The package returns the entire batch job XML in its Xml property. It is this XML that the BatchSendMessages(SPMobileMessageBatchPackage) method sends to the messaging Web service.

We recommend that you include code that processes the list of reports returned by the BatchSendMessages(SPMobileMessageBatchPackage) method, logs successful messages, and responds to failures.

Other Web Service Methods

The SPMobileMessageWebService class has two other methods, GetUserInfo(String) and GetServiceInfo(), that act as proxies for the OMS Web Methods GetUserInfo and GetServiceInfo respectively.

Developing for Other Protocols

Microsoft does not support deriving from any of the classes in Microsoft.SharePoint.MobileMessage to create a mobile messaging solution does not use the OMS Protocol. If you want your solution to work with such an MSP that does not use OMS, consider creating a Web service that acts as a middle layer between SharePoint Foundation mobile messaging APIs and the MSP that uses another protocol. The service would accept OMS protocol messages from SharePoint Foundation and transform them into messages appropriate for the MSP that uses the other protocol.