Michael Kwayisi

SMSGH Unity API .NET4+ Client Library

Twitter · Facebook
Alternative .NET client library of the SMSGH Unity APIAlternative .NET client library of the SMSGH Unity API

This is an alternative client library implementation of SMSGH's Unity API which allows sending of text messages and other bulk and premium messaging activities. This implementation came about when during my usage of the official .NET library, I found it tedious and not sufficiently idiomatic according to the contemporary coding grammar of C#.NET. It felt rigid and contrived, like it was auto-generated by some futuristic supercomputer. I therefore decided to write this alternative to make interaction with the API feel natural, easy, and intuitive but not too dumb simple so as to take away the programmer's creative aptitude and subject their intellect to that of a chicken.

Getting started with the API requires you to generate your client ID and secret combination in your SMSGH Unity account. (Alternatively, you may use an OAuth access token but that one can be very, very long—like, 800+ bytes.[1]) But when it comes to choosing the client to talk to the API, I do not recommend the current .NET library provided by SMSGH because it's infested with hideous bugs and glitches. Moreover, it's slow and very insecure. Did I mention "buggy," and sloooooow? H'm, I think I did. But worry not, my dear, for all these distressing issues that you are hearing of have beautifully been resolved in the alternative solution that I'm offering you this day!

This library is designed to be simple and intuitive so you surely don't need any separate reference manual (which nobody reads anyway) aside from the accompanying XML documentation which comes in handy when coding from within an enabling integrated development environment such as Microsoft Visual Studio. For this reason, exhaustive concepts and use cases of the library are not presented herein, but rather highlights of key fundamental reasons why you may want to choose this over the official stock implementation. So if you're ready, then let's begin with the subject of design—before any bug could crawl out of the SMSGH libraries to bite us in the backside!

Design: Consistency, coherency, and ease-of-use

The SMSGH Unity API implementation itself is somewhat green and plainly lacks a touch of fine art. For example, when querying for a contact group, there is no good reason to include AccountId (which tells the owner of the instance) in among the properties.[2] Regarding terminology, the same can be remarked about the AccountId, AccountManager, AccountNumber, and AccountStatus properties of the account profile object. Since we are dealing with an account object, wouldn't it be simpler—yet elegant—to just say Id, Manager, Status, etc.? Well, as I'm a bit allergic to perfunctory work, I have taken the trouble to fix these axiomatic blemishes in the client library.

Another case is the inconsistent behavior of the official client library when an object is updated. For instance, when a sender is updated, the updated sender is returned; also for message templates and account settings. However, when a contact is updated, a boolean value is returned—which is always true, by the way; contact groups and account contacts too. Although this is as a result of the API itself, I've standardized it by always returning the object being updated upon success. Yet another issue is when you're attempting to retrieve an object by an identifier. If not found, the API rightly returns a 404 status code; the library, on the other hand, throws an exception! Terrible.

Hopping to the subject of ease-of-use, suppose you are to query all the contacts in your SMSGH Unity account, this is how you would do it with the official .NET client library:

// using smsghapi_dotnet_v2.Smsgh;
uint page = 1, size = 100;
ApiList<Contact> contacts;
var capi = new ContactApi(new ApiHost(new BasicAuth("{id}", "{secret}")));
do {
foreach (var contact in contacts = capi.GetContacts(page, size))
} while (page++ < contacts.TotalPages);

Now, compare the above with what I'm offering:

// using Kwayisi.Smsgh.Unity;
foreach (var contact in new Api("{id}", "{secret}").Contacts)

Yes, I believe code should be that simple! Besides, if you have, say, a thousand contacts saved in your account, the official library will be making 10 API requests in total (regarding the sample code above) each time pulling in 100 contacts.[3] In contrast, the latter code would make just one, single, unary request to the API and you'll still get all your contacts. Isn't it cool that you could write all those mind-numbing lines in just two literal lines of code instead? Don't even get me started on the horrible "smsghapi_dotnet_v2" namespace which totally sucks to the marrow. Weird stuff.

To close this section on design, please allow me to touch on the matter of exception handling. You see, when an error of any kind occurs in the official client library, it throws a direct instance of the System.Exception class which is an act that could easily pass as one of the worst crimes against humanity! Okay, that might have been a little exaggerated but my point is, the library affords you no way to distinguish between errors from it and those from other parts of your code within the same block. This is awful because it poses a security threat to any application built on top of it no matter how trivial its subtlety, which aptly leads us to our next subject of discussion—

Security: Exceptions, bugs, and vulnerabilities

Consider this little piece of code: new MessagingApi(new ApiHost()); It doesn't work; it results in a NullReferenceException when run. The reason is simple: the library expects you to have set your credentials before creating the MessagingApi instance which was clearly not what happened. But instead of it checking the object before use, it doesn't do so thereby generating the exception. This raises some serious security concerns since there is a risk—albeit minute—of segfaulting the containing DLL causing the whole of your software to crash without recovery, potentially losing or corrupting user data in the process. Libraries must be stable and robust which is sadly not the case here.

There are other areas too where the official Unity API client library ingloriously fails. To exemplify an instance, check out the following code:

// using smsghapi_dotnet_v2.Smsgh;
class Mapi : MessagingApi {
public ApiHost ApiHost { get { return Host; } }
public Mapi(ApiHost apiHost) : base(apiHost) {}
var m1 = new Mapi(new ApiHost(new OAuth("{token}")) { Hostname = "host1" });
var m2 = new Mapi(new ApiHost(new OAuth("{token}")) { Hostname = "host2" });

You could see from above that two instances of Mapi are created with hostname values "host1" and "host2" respectively. You would naturally then expect the output of the program (which is supposed to be the hostname of the first instance) to be "host1" but—surprise!—it's "host2" instead. Gee, how come? The Host property in the AbstractApi class (not shown) which MessagingApi inherits from is static! So although you would think that you've created multiple instances, no, you're actually using a single, global, static class variable! Any later instantiation of any of the classes that inherit from AbstractApi will consequently overwrite all previous "instances." This is a disaster!

Perhaps now you're wondering, "Under what circumstances could this deadly bug bite me?" Hmm, in fact, several. For starters, the library fails catastrophically in any asynchronous/multi-threaded environment. To vividly illustrate the kind of ruin and havoc that this library could wreak upon you and your descendants, let us consider the following scenario: You have developed an app that sends daily "Good morning" messages to SMSGH customers. Since the app is free, the recipients are to cover the messaging costs themselves, hence, have granted you the necessary permissions via an OAuth access token. So, below, you write the code to send the first batch of 100 messages:

// using smsghapi_dotnet_v2.Smsgh;
foreach (var user in db.Users.Take(100))
RunAsync(() => new MessagingApi(new ApiHost(new OAuth(user.AccessToken)))
.SendQuickMessage("Me", user.MobileNumber, "Good morning.", false));

You would expect that each user's SMSGH Unity account be charged since you are evidently using their OAuth access token to send their individual messages. Wrong! Suppose it takes as much time for SendQuickMessage to make the first HTTP request to the API as the asynchronous thread takes to create all the MessagingApi instances—which is typical and not anything out of the ordinary to happen in such an environment as the one shown above[4]—then there will indeed be 100 messages sent to the targeted users, only that 99 of them will not be paying for their messages at the expense of the 100th! O yes, the library sucks that much. But hang on; lemme fetch the final nail.

Performance: Latency and system resource usage

According to Vanessa Williams, 'sometimes . . . you save the best for last,' so here I present to you the best part of this treatise: code execution performance. First off, let's have a look at the assembly size. The file size of the official DLL for .NET 4.0 is 168,448 bytes versus what I'm offering which is 38,912 bytes. A simple arithmetic tells you that the former requires four times as much memory space for the operating system to load the executable in comparison with the latter. As the figures clearly speak for themselves, choosing what I'm putting on the table over the official library leaves your application with more precious free memory resulting in a performance boost.

Another detail of notice is the manner in which ApiList<T> converts the JSON data that it receives from the API to their respective .NET types. The procedure that the constructor uses is primitive, inefficient, and sometimes produces grossly inaccurate and misleading results.[5] A far better—and, as a matter of fact, easier—approach is to just let Newtonsoft's JsonSerializer deserialize the JSON data directly to their respective .NET assembly types. But even before a response is received from the API, the client library for some muddy reason sends a Content-Type header as part of its HTTP GET request which unnecessarily increases the request footprint. The list goes on forever.

Now, having made doubtlessly clear the inefficiencies and thriftlessness of the .NET client library provided by SMSGH, it's about time we ran a benchmark test to see how the numbers come out.

// using smsghapi_dotnet_v2.Smsgh;
var start = DateTime.Now;
int count = 0;
uint page = 0, size = 100;
ApiList<Message> apiList;
var mapi = new MessagingApi(new ApiHost(new BasicAuth("{id}", "{secret}")));
do {
apiList = mapi.GetMessages(null, null, page * size, size, false, null);
foreach (var m in apiList) {}
count += apiList.Items.Count;
} while (count < 5000 && ++page < apiList.TotalPages);
Console.WriteLine("Time taken: {0}", DateTime.Now - start);

// using Kwayisi.Smsgh.Unity;
var start = DateTime.Now;
foreach (var m in new Api("{id}", "{secret}").Messages.Filter(take: 5000)) {}
Console.WriteLine("Time taken: {0}", DateTime.Now - start);

As strange as it may sound, you should really count yourself lucky if you're able to successfully run the first part of the benchmark code above without running into sporadic exceptions with cryptic messages such as “Additional text encountered after finished reading JSON content . . .” But what were the results like? C'mon, don't pretend you don't know who's gonna win this, eh? Anyway, here are the numbers: 50:5 HTTP requests, 131:47 request payload delta, and 139:19 seconds execution time. As you can see, regarding the latter, performance has gone through the roof and shattered the whole building into atomic pieces! Yippee! Yay! Yfkjqozhndx~?!@#$%+—

So now, beloved friends, I guess all that could be said about the official .NET client library and that which I'm offering have been said and, hopefully, have gone down the right paths. Although the libraries for other languages were not discussed herein, it's likely that they are also suffering from similar defectiveness, so be careful in your selection. The word of advice here is this: if you can write your own code for the API, then please certainly do so. Otherwise, may the right hand of your God guide you, and protect you, and keep you sane, as you traverse the landmine of evil bugs in your usage of the current API client libraries provided by SMSGH. Auf Wiedersehen!

Below you may download the pre-compiled binaries and source code of this client library. Please note that the library requires the Newtonsoft JSON.NET library and Microsoft .NET Framework 4.0 or later. Also, if you have the option to compile from source together with your project's, it is recommended that you do so in order to benefit from the compiler's optimizations.

ksu-0.1-bin.zipPre-compiled binaries (including JSON.NET)202.54 KiB
ksu-0.1-src.zipSource code (including a Visual C# project file)17.91 KiB

The license that comes with this software (both source code and compiled binaries) allows you to distribute, tweak, and build upon your own work, even commercially, provided the author is credited for the original creation. See the in-package LICENSE.txt for additional information.


  1. ^ The access token is so long because it is self-descriptive, that is, the various API scopes are encoded inside the token itself so no database lookups or such are needed by the resource server upon receiving it; pretty much everything that the server needs to know about the request and the originating client are right there in the token. Of course, the authorization server does verify the authenticity of the token before proxying it over to the resource server.
  2. ^ The said property is obviously a field in the contact groups table referencing an account table somewhere to determine ownership of each row, but it doesn't help being part of the API result. This is a clear case of the developer just dumping whatever is inside the database tables without much thought of whether such information are relevant in fulfilling an API request. Could it be, therefore—by inference only—that this cavalier attitude has been carried forward to build other parts of the SMSGH platform resulting in a vulnerable infrastructure somehow?
  3. ^ You may have noticed that the buffered page size of the API requests in the former code sample is 100 thereby resulting in 10 separate requests to retrieve 1,000 contacts. In fact, the API supports up to 1,000 contacts on a single page but the current implementation of the official library is buggy regarding its deserialization of JSON data if the page size exceeds 100-ish, hence, that. Needless to say, mine handles these situations impeccably well :)
  4. ^ Creating TCP connections could actually take quite some time, especially when communications are going to be encrypted in which case SSL handshakes must take place. In a little experiment I performed, connections sometimes took up to 450ms to be created, and approximately thrice as much time to complete the SSL handshakes bringing the total time consumption to ~1.8 seconds. Obviously, instantiating 100 simple objects won't take that long.
  5. ^ I say “grossly inaccurate and misleading” because when querying for messages, for instance, the API does not return a Count property in its response. Accessing the said property from the ApiList<Message> object returned by the GetMessages method however gives you "0" (zero) which if you're not aware of the actual behavior of the API would induce you to think that indeed you have no messages in your account. In my implementation, however, I devised a clever way to return the actual messages count—which you may read the code yourself to find out how :)

Comments (2)

  1. GeorgeGeorge
    Jun 17, 2016 10:40 GMT

    Hi Michael, good job on the library. I however know that the library you are bashing so hard is open source. I expect you to contribute to it to make it better.
    What you have done by this long talk is display some good levels of arrogance .
    I will advice that you contribute to open source projects such as these because that is what will make you more appreciated and seen as a great programmer.

    1. Michael KwayisiMichael Kwayisi
      Jun 17, 2016 12:16 GMT

      You can either see this essay as a 'bash' or simply have a laugh and move on. I accept no blame if one misses the spirit in which it was written. Re arrogance, it's an attribute that has characterized programmers since they began. In fact, the widely known three great virtues of a programmer are laziness, impatience, and hubris, the last being synonymous with arrogance. So, in effect, you're just affirming my status as a programmer.

      If you compare the source code, you'll realize that my design approach is entirely different from SMSGH's. 'Contributing' would have meant rewriting everything from scratch which, when I did, came at the cost of sacrificing compatibility with .NET versions prior to 4. This library is therefore meant to be an alternative but not a replacement. (The bugs have been made known to those who can fix them since circa March 2015.) And yes, I do contribute my fair share to the FOSS community albeit pseudonymously.

  • Showing 1 - 1 of 1
NOTE: You are replying to 's comment. [Cancel]